Hello!
So basically I am trying to program my syringe pump. I want to program it so that incase of any leakages it can correct the pressure leak using PID control. I have 3 zones of pressure. After staying at one zone it should gain pressure and move to another. Everything seems to work fine for the first zone but unfortunately it is not moving to the 2nd zone and 3rd zone. I have tried playing with logic and everything, nothing helped. Would be nice if anyone can help me out.
here is my code:
#include <Adafruit_MPRLS.h>
#include <PID_v1.h>
#include <Stepper.h>
#include <Wire.h>
// Define the pins for the stepper motor driver
const int stepPin = 2;
const int dirPin = 5;
const int enPin = 8;
const int stepYPin = 3; //Y.STEP
const int dirYPin = 6; // Y.DIR
// Define the number of steps for the stepper motor and the speed
const int stepsPerRevolution = 200;
const int motorSpeed = 40;
#define RESET_PIN -1 // set to any GPIO pin # to hard-reset on begin()
#define EOC_PIN -1 // set to any GPIO pin to read end-of-conversion by pin
Adafruit_MPRLS mpr = Adafruit_MPRLS(RESET_PIN, EOC_PIN);
// Define the setpoint pressure values for each zone
const float setpoint1 = 1094.7;
const float setpoint2 = 1177.8;
const float setpoint3 = 1297.3;
// Define the PID constants for each zone
const double kp1 = 1;
const double ki1 = 0.1;
const double kd1 = 0.05;
const double kp2 = 1;
const double ki2 = 0.1;
const double kd2 = 0.05;
const double kp3 = 1;
const double ki3 = 0.1;
const double kd3 = 0.05;
// Define the minimum and maximum pressure values for each zone
const float minPressure1 = 980.0;
const float maxPressure1 = 1440.0;
const float minPressure2 = 980.0;
const float maxPressure2 = 1440.0;
const float minPressure3 = 980.0;
const float maxPressure3 = 1440.0;
// Define the hold time in milliseconds for each zone
const int holdTime1 = 60000;
const int holdTime2 = 120000;
const int holdTime3 = 180000;
// Initialize the stepper motor object
Stepper myStepper(stepsPerRevolution, stepPin, dirPin);
// Initialize the PID objects for each zone
double Input1 = 0, Input2 = 0, Input3 = 0;
double Output1 = 0, Output2 = 0, Output3 = 0;
PID pid1(&Input1, &Output1, (double*)&setpoint1, kp1, ki1, kd1, DIRECT);
PID pid2(&Input2, &Output2, (double*)&setpoint2, kp2, ki2, kd2, DIRECT);
PID pid3(&Input3, &Output3, (double*)&setpoint3, kp3, ki3, kd3, DIRECT);
// Initialize variables to keep track of the current zone and the time elapsed in that zone
int currentZone = 1;
unsigned long timeElapsed = 0;
void setup() {
// Set up the serial communication
Serial.begin(115200);
if (! mpr.begin()) {
Serial.println("Failed to communicate with MPRLS sensor, check wiring?");
while (1) {
delay(10);
}
}
Serial.println("Found MPRLS sensor");
// Set up the pins for the stepper motor driver
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(enPin, OUTPUT);
digitalWrite(enPin, LOW);
// Set the motor speed
myStepper.setSpeed(motorSpeed);
// Set the sample time for the PID loops
pid1.SetSampleTime(100);
pid2.SetSampleTime(100);
pid3.SetSampleTime(100);
// Enable the PID loops
pid1.SetMode(AUTOMATIC);
pid2.SetMode(AUTOMATIC);
pid3.SetMode(AUTOMATIC);
// Move the stepper motor to the starting position
//myStepper.step(100);
}
void loop() {
unsigned long currentTime = millis();
// Read the current pressure from the sensor
float pressure = mpr.readPressure();
// Check if the hold time for the current zone has elapsed
if (currentZone == 1 && (currentTime - timeElapsed) >= holdTime1) { //
// Move to the next zone
currentZone = 2;
timeElapsed = currentTime;
// Reset the PID controller for the new zone
pid1.SetMode(MANUAL);
pid2.SetMode(AUTOMATIC);
pid3.SetMode(MANUAL);
pid1.SetOutputLimits(0, 0);
pid3.SetOutputLimits(0, 0);
} else if (currentZone == 2 && (currentTime - timeElapsed) >= holdTime2) {
// Move to the next zone
currentZone = 3;
timeElapsed = currentTime;
// Reset the PID controller for the new zone
pid1.SetMode(MANUAL);
pid2.SetMode(MANUAL);
pid3.SetMode(AUTOMATIC);
pid1.SetOutputLimits(0, 0);
pid2.SetOutputLimits(0, 0);
} else if (currentZone == 3 && (currentTime - timeElapsed) >= holdTime3) {
// Hold the last zone indefinitely
pid1.SetMode(MANUAL);
pid2.SetMode(MANUAL);
pid3.SetMode(MANUAL);
pid1.SetOutputLimits(0, 0);
pid2.SetOutputLimits(0, 0);
pid3.SetOutputLimits(0, 0);
timeElapsed = currentTime;
}
// Set the input values for each PID loop
if (currentZone == 1) {
Input1 = pressure;
}
if (currentZone == 2) {
Input2 = pressure;
}
if (currentZone == 3) {
Input3 = pressure;
}
// Compute the outputs for each PID loop
pid1.Compute();
pid2.Compute();
pid3.Compute();
// Set the stepper motor direction based on the current zone and the PID output
int dir = 0;
if (currentZone == 1) {
dir = Output1 > 0 ? HIGH : LOW;
} else if (currentZone == 2) {
dir = Output2 > 0 ? HIGH : LOW;
} else if (currentZone == 3) {
dir = Output3 > 0 ? HIGH : LOW;
}
digitalWrite(dirPin, dir);
// Check if the pressure has reached the setpoint pressure
if (currentZone == 1 && pressure >= setpoint1) {
Output1 = 0; // set the output of the PID loop to zero
digitalWrite(dirPin, HIGH); // stop the stepper motor
} else if (currentZone == 2 && pressure >= setpoint2) {
Output2 = 0; // set the output of the PID loop to zero
digitalWrite(dirPin, HIGH); // stop the stepper motor
} else if (currentZone == 3 && pressure >= setpoint3) {
Output3 = 0; // set the output of the PID loop to zero
digitalWrite(dirPin, HIGH); // stop the stepper motor
}
else {
myStepper.step(25);
}
// Check if the pressure is outside the allowed range for the current zone
if (currentZone == 1 && (pressure < minPressure1 || pressure > maxPressure1)) {
Serial.println("Error: Pressure outside allowed range for zone 1");
// Stop the motor and turn off the driver
myStepper.step(0);
digitalWrite(enPin, LOW);
// Disable the PID loops
pid1.SetMode(MANUAL);
pid2.SetMode(MANUAL);
pid3.SetMode(MANUAL);
pid1.SetOutputLimits(0, 0);
pid2.SetOutputLimits(0, 0);
pid3.SetOutputLimits(0, 0);
// End the program
while (true) {}
} else if (currentZone == 2 && (pressure < minPressure2 || pressure > maxPressure2)) {
Serial.println("Error: Pressure outside allowed range for zone 2");
// Stop the motor and turn off the driver
myStepper.step(0);
digitalWrite(enPin, LOW);
// Disable the PID loops
pid1.SetMode(MANUAL);
pid2.SetMode(MANUAL);
pid3.SetMode(MANUAL);
pid1.SetOutputLimits(0, 0);
pid2.SetOutputLimits(0, 0);
pid3.SetOutputLimits(0, 0);
// End the program
while (true) {}
} else if (currentZone == 3 && (pressure < minPressure3 || pressure > maxPressure3)) {
Serial.println("Error: Pressure outside allowed range for zone 3");
// Stop the motor and turn off the driver
myStepper.step(0);
digitalWrite(enPin, LOW);
// Disable the PID loops
pid1.SetMode(MANUAL);
pid2.SetMode(MANUAL);
pid3.SetMode(MANUAL);
pid1.SetOutputLimits(0, 0);
pid2.SetOutputLimits(0, 0);
pid3.SetOutputLimits(0, 0);
// End the program
while (true) {}
}
// Print the pressure and PID output values to the serial monitor
Serial.print("Zone ");
Serial.print(currentZone);
Serial.print(": Pressure=");
Serial.print(pressure);
Serial.print(", Output=");
if (currentZone == 1) {
Serial.print(Output1);
} else if (currentZone == 2) {
Serial.print(Output2);
} else if (currentZone == 3) {
Serial.print(Output3);
}
Serial.println();
// Wait for a short time to allow the pressure to stabilize
}