Untitled
Anonymous
plain_text
03/22/2026 12:21 PM
6.1 KB
10
Indexable
#include <SoftwareSerial.h>
#include <Servo.h>
// --- PIN DEFINITIONS ---
#define IBUS_RX_PIN 4
#define IBUS_TX_PIN 5
#define SERVO_LEFT_PIN 9
#define SERVO_RIGHT_PIN 10
// --- FLIGHT SETTINGS ---
#define WING_CENTER 90
#define TARGET_AMPLITUDE 70 // Reduced to 70 for a safe 140-degree total sweep
#define STEER_MAX_OFFSET 45 // Max steering offset
#define SERVO_MIN_ANGLE 20 // Pulled in to prevent bottom-end dwelling
#define SERVO_MAX_ANGLE 160 // Pulled in to prevent top-end dwelling
#define SPEED_MIN_MS 450 // FASTEST speed (restored for snappier flapping)
#define SPEED_MAX_MS 1500 // SLOWEST speed
// --- HARDWARE OBJECTS ---
SoftwareSerial ibus_serial(IBUS_RX_PIN, IBUS_TX_PIN);
Servo servoLeft;
Servo servoRight;
// --- GLOBAL FLIGHT STATE ---
int channels[10];
bool isSignalValid = false;
float currentSpeed = 0.0;
int currentSteerOffset = 0;
float phase = 0.0;
unsigned long lastUpdate = 0;
void setup() {
Serial.begin(115200);
ibus_serial.begin(115200);
// Electrical calibration bounds
servoLeft.attach(SERVO_LEFT_PIN, 600, 2400);
servoRight.attach(SERVO_RIGHT_PIN, 600, 2400);
// Initialize at 90 degrees
servoLeft.write(WING_CENTER);
servoRight.write(WING_CENTER);
Serial.println("🦋 Bionic Butterfly - Glide & Trim Fixed");
}
void loop() {
fetchRadioSignals();
if (!isSignalValid) {
engageFailsafe();
return;
}
calculateFlightDynamics();
updateWingServos();
delay(2);
}
void fetchRadioSignals() {
if (ibus_serial.available() >= 4 && ibus_serial.read() == 0x20 && ibus_serial.read() == 0x40) {
uint8_t buf[28];
for (int i = 0; i < 28; i++) {
unsigned long t = millis();
while (!ibus_serial.available()) {
if (millis() - t > 10) return;
}
buf[i] = ibus_serial.read();
}
for (int i = 0; i < 10; i++) {
channels[i] = buf[i * 2] | (buf[i * 2 + 1] << 8);
}
}
int rawThrottle = channels[2];
if (rawThrottle > 900 && rawThrottle < 2100) {
isSignalValid = true;
} else {
isSignalValid = false;
}
}
void engageFailsafe() {
servoLeft.write(WING_CENTER);
servoRight.write(WING_CENTER);
phase = 0;
}
void calculateFlightDynamics() {
int rawThrottle = channels[2]; // Left stick Up/Down
int rawSteer = channels[0]; // Right stick Left/Right
// 1. Calculate Flapping Speed
if (rawThrottle > 1100) {
currentSpeed = (float)(rawThrottle - 1100) / 800.0;
currentSpeed = constrain(currentSpeed, 0.0, 1.0);
} else {
currentSpeed = 0.0;
}
// 2. Calculate Steering Offset
currentSteerOffset = 0;
if (rawSteer < 1450 || rawSteer > 1550) { // Deadzone
float steerNorm = (float)(rawSteer - 1500) / 500.0;
steerNorm = constrain(steerNorm, -1.0, 1.0);
currentSteerOffset = (int)(steerNorm * STEER_MAX_OFFSET);
}
}
void updateWingServos() {
// Determine where the wings should be pointing based on steering
int leftCenter = WING_CENTER - currentSteerOffset;
int rightCenter = WING_CENTER + currentSteerOffset;
// --- GLIDE MODE (Throttle is 0) ---
if (currentSpeed <= 0.01) {
// Write steering offsets but do not flap
servoLeft.write(constrain(leftCenter, SERVO_MIN_ANGLE, SERVO_MAX_ANGLE));
servoRight.write(constrain(rightCenter, SERVO_MIN_ANGLE, SERVO_MAX_ANGLE));
phase = 0; // Reset wave for next flap
return;
}
// --- FLAPPING MODE ---
unsigned long now = millis();
unsigned long dt = now - lastUpdate;
lastUpdate = now;
float cycleDuration = map(currentSpeed * 1000, 1, 1000, SPEED_MAX_MS, SPEED_MIN_MS);
float phaseStep = (TWO_PI / cycleDuration) * dt;
phase += phaseStep;
if (phase > TWO_PI) phase -= TWO_PI;
float sineVal = sin(phase);
// Dynamic Amplitude Calculation
int maxLeftAmplitude = min(SERVO_MAX_ANGLE - leftCenter, leftCenter - SERVO_MIN_ANGLE);
int maxRightAmplitude = min(SERVO_MAX_ANGLE - rightCenter, rightCenter - SERVO_MIN_ANGLE);
int safeAmplitude = min(maxLeftAmplitude, maxRightAmplitude);
int actualAmplitude = min(TARGET_AMPLITUDE, safeAmplitude);
// Calculate final moving angles
int leftAngle = leftCenter + (int)(sineVal * actualAmplitude);
int rightAngle = rightCenter - (int)(sineVal * actualAmplitude);
// Hard clamp safety net
leftAngle = constrain(leftAngle, SERVO_MIN_ANGLE, SERVO_MAX_ANGLE);
rightAngle = constrain(rightAngle, SERVO_MIN_ANGLE, SERVO_MAX_ANGLE);
servoLeft.write(leftAngle);
servoRight.write(rightAngle);
}Editor is loading...
Leave a Comment