///////////////////////////////////////////////////////
//
// Luca Amore
// https://www.lucaamore.com
//
///////////////////////////////////////////////////////
#include <stdio.h>
#include <math.h>
#include <QuickPID.h>
#include <ESP32Servo.h>
#define PENDOLUM_PIN 18
#define FORCE_PIN 5
#define HORZ_PIN 35
#define VERT_PIN 32
#define SEL_PIN 25
#define ENABLE_CRASH_CONTROL
Servo servo_pendulum;
// Variables and parameters of the PID
float setpoint, input, output;
//QuickPID myPID(&input, &output, &setpoint);
const float Kp = 5, Ki = 10, Kd = 2;
QuickPID myPID(&input, &output, &setpoint, Kp, Ki, Kd, myPID.Action::direct);
// Parameters of the pendulum
const double g = 9.81; // gravitational acceleration
const double l = 1.0; // length of the pendulum
const double b = 0.1; // damping coefficient (friction)
const double m = 1.0; // mass of the pendulum
// Simulation parameters
const double dt = 0.0001; // time step
// Function to update the state of the pendulum
void updatePendulum(double *theta, double *omega, double F) {
double dtheta = *omega;
double domega = (g / l) * sin(*theta) - (b / m) * (*omega) + (F / (m * l));
// Update the state using Euler's method
*theta += dtheta * dt;
*omega += domega * dt;
#ifdef ENABLE_CRASH_CONTROL
// Crash control
if (*theta > M_PI/2){
*omega = 0;
*theta = M_PI/2;
} else if (*theta < -M_PI/2) {
*omega=0;
*theta = -M_PI/2;
}
#endif
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Hello, ESP32!");
myPID.SetTunings(Kp, Ki, Kd);
myPID.SetMode(myPID.Control::automatic);
pinMode(VERT_PIN, INPUT);
pinMode(HORZ_PIN, INPUT);
pinMode(SEL_PIN, INPUT_PULLUP);
servo_pendulum.attach(PENDOLUM_PIN);
servo_pendulum.write(0);
}
void loop() {
double theta = 0; // initial angle (45 degrees)
double omega = 0.0; // initial angular velocity
double F = 0.0; // external force applied to the pendulum
double t=0;
while(1) {
int horz = analogRead(HORZ_PIN);
int vert = analogRead(VERT_PIN);
int sel = digitalRead(SEL_PIN) == LOW;
if (sel){
theta=0;
omega=0;
}
t += dt;
F=0;
//apply PID gains
setpoint = 50;
input = map(theta * (180.0 / M_PI), -90, 90, 0, 100);
myPID.SetOutputLimits(-5000, 5000);
myPID.Compute();
F=(-vert+2048)*1000;
F+=output;
updatePendulum(&theta, &omega, F);
servo_pendulum.write(theta * (180.0 / M_PI) + 90);
//Serial.print("Time: ");
//Serial.print(t, 2);
Serial.print(", A: ");
Serial.print(theta * (180.0 / M_PI), 2);
Serial.print(", V: ");
Serial.print(omega * (180.0 / M_PI), 2);
//Serial.print(", Force: ");
//Serial.print(F, 2);
Serial.print(", PID: ");
Serial.print(output, 2);
//Serial.print(", P: ");
//Serial.print(myPID.GetPterm(), 2);
//Serial.print(", I: ");
//Serial.print(myPID.GetIterm(), 2);
//Serial.print(", D: ");
//Serial.print(myPID.GetDterm(), 2);
Serial.println();
}
Serial.print("Someting is under control!");
}