-
Notifications
You must be signed in to change notification settings - Fork 0
/
MEGA_laser_FlyerV2.ino
135 lines (105 loc) · 3.19 KB
/
MEGA_laser_FlyerV2.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <Wire.h>
#include <Adafruit_GPS.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Servo.h>
#include <MPU6050_tockn.h>
#include <PID_v1.h>
// Constants
const int opticalSensorPin = 2;
const int servoXPin = 9;
const int servoYPin = 10;
// Variables
int opticalSensorValue;
int servoXPosition = 90;
int servoYPosition = 90;
// Target position
float targetX = 0;
float targetY = 0;
// Servo objects
Servo servoX;
Servo servoY;
// BME280 object
Adafruit_BME280 bme;
// MPU6050 object
MPU6050 mpu6050(Wire);
// GPS object
Adafruit_GPS GPS(&Serial1);
// PID Controllers
double inputX, inputY, outputX, outputY;
double setpointX = 0, setpointY = 0;
double kP = 1, kI = 1, kD = 1;
PID pidX(&inputX, &outputX, &setpointX, kP, kI, kD, DIRECT);
PID pidY(&inputY, &outputY, &setpointY, kP, kI, kD, DIRECT);
void setup() {
Serial.begin(115200);
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
pinMode(opticalSensorPin, INPUT);
servoX.attach(servoXPin);
servoY.attach(servoYPin);
servoX.write(servoXPosition);
servoY.write(servoYPosition);
// Initialize MPU6050
Wire.begin();
mpu6050.begin();
mpu6050.calcGyroOffsets(true);
// Initialize GPS
GPS.begin(9600);
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
GPS.sendCommand(PGCMD_ANTENNA);
// Initialize PID controllers
pidX.SetMode(AUTOMATIC);
pidY.SetMode(AUTOMATIC);
}
void loop() {
// Update GPS data
GPS.read();
if (GPS.newNMEAreceived()) {
if (!GPS.parse(GPS.lastNMEA())) {
return;
}
}
opticalSensorValue = digitalRead(opticalSensorPin);
float currentAltitude = bme.readAltitude();
// Update MPU6050 data
mpu6050.update();
// Guide the canister to the laser if detected
if (opticalSensorValue == HIGH) {
guideCanisterToTarget(currentAltitude);
}
}
void guideCanisterToTarget(float currentAltitude) {
// Get the current position of the canister
inputX = getCurrentX();
inputY = getCurrentY();
// Set the target position of the canister
setpointX = targetX;
setpointY = targetY;
// Compute the PID controller output
pidX.SetTunings(Kp, Ki, Kd);
pidY.SetTunings(Kp, Ki, Kd);
pidX.Compute();
pidY.Compute();
// Calculate speed and trajectory adjustments based on altitude
float altitudeFactor = calculateAltitudeFactor(currentAltitude);
outputX *= altitudeFactor;
outputY *= altitudeFactor;
// Update servo positions based on the PID output
servoXPosition = constrain(servoXPosition + outputX, 0, 180);
servoYPosition = constrain(servoYPosition + outputY, 0, 180);
// Write the updated servo positions
servoX.write(servoXPosition);
servoY.write(servoYPosition);
}
float calculateAltitudeFactor(float currentAltitude) {
// Implement a function to calculate a factor based on the altitude
// This factor should be used to adjust the control output based on the canister's altitude
// The specific function can be derived through simulations, real-world testing, or a combination of both
// For example, return a linear or non-linear function of currentAltitude
// A simple example:
return 1.0 - (currentAltitude / maxAltitude);
}