please find below the current code for an arduino project which makes 4 ventillator to rotate in a custom RPM level.
My initial problem which i can’t solve is to change the RPM level of rotation after it starts on the first set level.
So if I type ‘999’ in the arduino IDE’s serial monitor then it waits for the desired RPM, lets say 1000. Because it has 4 ventillators I have to write this 4 times for example: 999 then 1000 then 999 then 1000 then 999 then 1000 then 999 then 1000. In this case it starts to rotate each ventillator on 1000 RPM. And if I want to change the RPM I need to kill the process and just start again from the begining with the other RPMs which makes this non optimal.
I’m working on a different setup beacuse I dont really need 4 ventillators only 1 so my question would be how to rewrite this code to so it would only need me to write 999 then the desired RPM which could be changed via the serial monitor.
Probably it is obvious that I can’t code, I’m just working on a project which uses this ventillators and this inherited code really frustrates me so please help to build a new one with one ventillator and changeable RPMs.
I tried to make some changes with a following theory but still couldn’t change the parameter while running.
if (Serial.available() > 0)
{
/*there is new data from the user --> PWM reload*/
}
void CheckSerialInput()
{
if (Serial.available() > 0)
{
/*use common target*/
double rpmGoal = Serial.parseInt();
Serial.print("RPM goal set to");
Serial.println(rpmGoal);
for (int index = 0; index < numControllers; index++)
{
controllers[index].pidData->SET(rpmGoal);
}
}
}`
Thanks in advance!
//add library PID by Brett Beauregard
#include <PID_v1.h>
const int numControllers = 4; //Number of controller circuits
const long slowRaiseTimePerStep = 2000; //Time between 2 steps while slowly raising the PWM
const int potmeterEpsilon = 5; //Potmeter reading inaccuracy, changes smaller than epsilon will be neglected
const int analogSetTime = 20; //Time to wait before reading next potmeter value
const int highPulsePerRotation = 4; //HIGH Pulse per rotation (how many pulseIns happen in a single rotation)
const int badMeasurementLimit = 500; //PulseIn times measured lower than this are discarded (noise)
const int slowRaiseMin = 160; //Starting PWM for pid controlled mode early slow raise
const int slowRaiseMax = 180; //Maximal PWM for pid controlled mode early slow raise
enum Mode {
Controlled,
SimplePWM,
Potmeter,
Restart
};
struct PinMapping {
int feedback; //Feedback pin to read current RPM
int pwm; //Pin to write PWM output to
int potmeter; //Potmeter pin to read manual goal from
PinMapping (int feedback, int pwm, int potmeter) :
feedback (feedback),
pwm (pwm),
potmeter (potmeter)
{ }
};
struct PotmeterData {
int goal = 0;
int epsilon;
long lastMeasure = 0;
PotmeterData (int epsilon = potmeterEpsilon) :
epsilon (epsilon)
{ }
bool ReadPWMGoal (int pin)
{
if(millis() - lastMeasure < analogSetTime) {
return false;
}
const double measurement = analogRead(pin) / 4;
lastMeasure = millis();
if(abs(goal - measurement) > epsilon)
{
goal = measurement;
return true;
}
return false;
}
};
struct PIDData {
double OUT = 0, IN = 0, SET;
double mult = 0.008;
PID pid;
PIDData (double SET) :
SET (SET),
pid (PID(&this->IN, &this->OUT, &this->SET, mult , mult , 0. , DIRECT))
{
pid.SetOutputLimits(30, 255);
pid.SetMode(AUTOMATIC);
pid.SetSampleTime(50);
}
void Reset (double IN, double OUT)
{
this->IN = IN;
this->OUT = OUT;
pid = PID(&this->IN, &this->OUT, &this->SET, mult , mult , 0. , DIRECT);
pid.SetOutputLimits(30, 255);
pid.SetMode(AUTOMATIC);
pid.SetSampleTime(50);
}
};
class Forgato {
private:
PinMapping pinMapping;
Mode mode = Mode::Restart;
PotmeterData potmeterData;
int pwmGoal;
PIDData pidData;
boolean pwmSet = false;
long slowRaiseStartTime = 0;
long lastLog = 0;
unsigned long previousPulseTimes[8];
public:
Forgato () :
pinMapping (PinMapping (0, 0, 0)),
mode (Mode::Restart),
pwmGoal (-1),
pidData (-1)
{}
Forgato (PinMapping pinMapping,
Mode mode,
int pwmGoal,
double rpmGoal) :
pinMapping (pinMapping),
mode (mode),
pwmGoal (pwmGoal),
pidData (rpmGoal)
{
pinMode(pinMapping.feedback, INPUT_PULLUP);
pinMode(pinMapping.pwm, OUTPUT);
analogWrite(pinMapping.pwm, 0);
}
void StoreRPM ()
{
//Get current pulseIn time
unsigned long T = pulseIn(pinMapping.feedback, HIGH);
//Only store if it is valid
if(T > badMeasurementLimit)
{
for(int i = 0; i < 7; i++)
previousPulseTimes[i] = previousPulseTimes[i+1];
previousPulseTimes[7] = 1.0 * T;
}
}
double GetAverageRPM()
{
double avg = 0.0;
for(int i = 0; i < 8; i++)
avg += previousPulseTimes[i];
avg /= 8;
//If avg is too small then let it be 1.0
if(avg < 1)
return 1.0;
else
return 60000000.0 / highPulsePerRotation / avg;
}
bool SlowRaisePWMFromTo(int from, int to)
{
if(!pwmSet) {
int value = from;
if (slowRaiseStartTime == 0) {
slowRaiseStartTime = millis();
value = from;
} else if (millis() > slowRaiseStartTime + (to - from) * slowRaiseTimePerStep) {
pwmSet = true;
value = to;
} else {
const int stepNum = (millis() - slowRaiseStartTime) * 1.0 / slowRaiseTimePerStep;
value = from + stepNum;
}
analogWrite(pinMapping.pwm, value);
Serial.print("PWM: ");
Serial.println(value);
StoreRPM();
Serial.print("RPM: ");
Serial.println(GetAverageRPM ());
return true;
}
return false;
}
void WriteNonPIDRPM()
{
if (millis() - lastLog > 1000)
{
Serial.println(GetAverageRPM ());
lastLog = millis();
}
}
void PIDControl()
{
pidData.IN = GetAverageRPM ();
//Compute
boolean comp = pidData.pid.Compute();
//If we made a step then set the PWM
if(comp)
{
analogWrite(pinMapping.pwm, pidData.OUT);
Serial.print("PWM set to: ");
Serial.println(pidData.OUT);
}
}
void Run ()
{
StoreRPM ();
Serial.print("RPM: ");
Serial.println(GetAverageRPM ());
switch(mode)
{
case Mode::Restart:
//Do nothing...
return;
case Mode::Controlled:
if (SlowRaisePWMFromTo(slowRaiseMin, slowRaiseMax)) {
pidData.Reset (slowRaiseMax, GetAverageRPM ());
}
PIDControl();
break;
case Mode::SimplePWM:
WriteNonPIDRPM();
SlowRaisePWMFromTo(90, pwmGoal);
break;
case Mode::Potmeter:
WriteNonPIDRPM();
if (potmeterData.ReadPWMGoal(pinMapping.potmeter)) {
analogWrite(pinMapping.pwm, potmeterData.goal);
Serial.print("PWM set to ");
Serial.println(potmeterData.goal);
}
break;
}
}
};
//////////////////////////////////////////////
PinMapping pinMappings[] = {PinMapping(8, 9, 1), PinMapping(7, 6, 3), PinMapping(4, 5, 5), PinMapping(2, 3, 7)};
Forgato controllers[4];
//////////////////////////////////////////////
void SetController (int index)
{
Serial.println("Waiting for order (at most 30 seconds...)");
Serial.println("999 for PID control");
Serial.println("555 for slow stepping to constant PWM");
Serial.println("13 for potmeter control");
//You have 30 seconds after start
Serial.setTimeout(30000);
int cmd = Serial.parseInt();
//Check for connection
if (cmd == 999) {
Serial.println("PID controlled PWM chosen");
Serial.println("Waiting for RPM goal...");
double prmGoal = 0.0;
double rpmGoal = Serial.parseInt();
Serial.print("RPM goal set to");
Serial.println(rpmGoal);
controllers[index] = Forgato (pinMappings[index], Mode::Controlled, -1, rpmGoal);
} else if (cmd == 555) {
Serial.println("Slow PWM raise chosen");
Serial.println("Waiting for PWM goal...");
int pwmGoal = Serial.parseInt();
Serial.print("PWM goal set to ");
Serial.println(pwmGoal);
controllers[index] = Forgato (pinMappings[index], Mode::SimplePWM, pwmGoal, -1);
} else if (cmd == 13) {
Serial.println("Potmeter controlled mode chosen");
Serial.println("Use the potmeter to adjust the PWM");
controllers[index] = Forgato (pinMappings[index], Mode::Potmeter, -1, -1);
} else {
Serial.println("Doing nothing... You should restart me");
controllers[index] = Forgato (pinMappings[index], Mode::Restart, -1, -1);
}
}
void setup() {
//---------------------------------------------- Set PWM frequency for D3 & D11 ------------------------------
//TCCR2B = TCCR2B & B11111000 | B00000001; // set timer 2 divisor to 1 for PWM frequency of 31372.55 Hz
TCCR2B = TCCR2B & B11111000 | B00000010; // set timer 2 divisor to 8 for PWM frequency of 3921.16 Hz
//TCCR2B = TCCR2B & B11111000 | B00000011; // set timer 2 divisor to 32 for PWM frequency of 980.39 Hz
//TCCR2B = TCCR2B & B11111000 | B00000100; // set timer 2 divisor to 64 for PWM frequency of 490.20 Hz (The DEFAULT)
//TCCR2B = TCCR2B & B11111000 | B00000101; // set timer 2 divisor to 128 for PWM frequency of 245.10 Hz
//TCCR2B = TCCR2B & B11111000 | B00000110; // set timer 2 divisor to 256 for PWM frequency of 122.55 Hz
//TCCR2B = TCCR2B & B11111000 | B00000111; // set timer 2 divisor to 1024 for PWM frequency of 30.64 Hz
Serial.begin(9600);
for (int index = 0; index < numControllers; index++) {
analogWrite (pinMappings[index].pwm, 0);
}
for (int index = 0; index < numControllers; index++) {
SetController (index);
}
}
void loop() {
for (int index = 0; index < numControllers; index++) {
controllers[index].Run ();
}
}
0