I am newbie to Arduino coding and i been trying to do project work. As the title says i am trying to control the DC motor speed using PID and IR sensor as a feedback system. Currently the coding can be uploaded but the reading in serial monitor is not stable and the system is not working properly. I am using LM298N to control the motor speed. I attach my coding together with reading i am getting. Please help me resolve the issue.
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <PID_v1.h>
int sensorvalue;
int state1 = HIGH;
int state2;
float rps;
float rpm;
long prevMillis = 0;
long interval = 200;
long currentTime;
long prevTime = 1;
long diffTime;
int sensorthreshold = 30;
int IN1 = 7; // DC motor pin
int IN2 = 8; // DC motor pin
int ENA = 9; // PWM DC motor pin
double Setpoint, Input, Output;
double Kp=2, Ki=5, Kd=1;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
// this value indicates the limit reading between dark and light,
// it has to be tested as it may change acording to the
// distance the leds are placed.
// to see what number is good, check the sensorvalue variable value
// as printed out in the serial monitor
void setup()
{
Serial.begin(9600);
pinMode (IN1, OUTPUT);
pinMode (IN2, OUTPUT);
pinMode (ENA, OUTPUT);
Input = analogRead(rpm);
Setpoint = 100;
//turn the PID on
myPID.SetMode(AUTOMATIC);
}
void loop()
{
analogWrite(ENA,150);
digitalWrite(IN1, HIGH);
digitalWrite(IN2,LOW);
sensorvalue = analogRead(0); // read from pin 0
if(sensorvalue < sensorthreshold)
state1 = HIGH;
else
state1 = LOW;
if(state2!=state1){ //counts when the state change, thats from (dark to light) or
//from (light to dark), remember that IR light is invisible to us.
if (state2>state1){
currentTime = micros(); // Get the arduino time in microseconds
diffTime = currentTime - prevTime; // calculate the time diff from the last meet-up
rps = 1000000/diffTime; // calculate how many rev per second, good to know
rpm = 60000000/diffTime; // calculate how many rev per minute
unsigned long currentMillis = millis();
// print to serial at every interval - defined at the variables declaration
if(currentMillis - prevMillis > interval){ // see if now already an interval long
prevMillis = currentMillis;
Serial.print(rps); Serial.print(" rps "); Serial.print(rpm); Serial.println(" rpm");
}
prevTime = currentTime;
}
state2 = state1;
}
{
Input = analogRead(rpm);
myPID.Compute();
analogWrite(9, Output);
}
/*
//only for testing to determine the sensorthreshold value
delay(500);
Serial.println(sensorvalue);
*/
}
I have also attach an image of the setup as reference and the serial monitor reading.
Thank you for time and your help is appreciated very much
If you are detecting the time for every revolution then don't bother to calculate RPS or RPM for speed control purposes - just work with millisecs or microsecs per revolution - just remember that a bigger number = slower speed.
This link has the code I use to detect motor speed. In another program I use PID with this to maintain speed.
I made the changes to the coding as mentioned but the reading in the serial monitor is still being the same. I having doubt about my PID coding part could sir help me in that part please. Thanks
The changes in the coding
int sensorvalue;
int state1 = HIGH;
int state2;
float rps;
float rpm;
unsigned long prevMillis = 0;
unsigned long interval = 200;
unsigned long currentTime;
unsigned long prevTime = 1;
unsigned long diffTime;
int sensorthreshold = 30;
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <PID_v1.h>
int sensorvalue;
int state1 = HIGH;
int state2;
float rps;
float rpm;
unsigned long prevMillis = 0;
unsigned long interval = 200;
unsigned long currentTime;
unsigned long prevTime = 1;
unsigned long diffTime;
int sensorthreshold = 30;
int IN1 = 7; // DC motor pin
int IN2 = 8; // DC motor pin
int ENA = 9; // PWM DC motor pin
double Setpoint, Input, Output;
double Kp=2, Ki=5, Kd=1;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
// this value indicates the limit reading between dark and light,
// it has to be tested as it may change acording to the
// distance the leds are placed.
// to see what number is good, check the sensorvalue variable value
// as printed out in the serial monitor
void setup()
{
Serial.begin(9600);
pinMode (IN1, OUTPUT);
pinMode (IN2, OUTPUT);
pinMode (ENA, OUTPUT);
Input = rpm;
Setpoint = 100;
//turn the PID on
myPID.SetMode(AUTOMATIC);
}
void loop()
{
analogWrite(ENA,150);
digitalWrite(IN1, HIGH);
digitalWrite(IN2,LOW);
sensorvalue = analogRead(0); // read from pin 0
if(sensorvalue < sensorthreshold)
state1 = HIGH;
else
state1 = LOW;
if(state2!=state1){ //counts when the state change, thats from (dark to light) or
//from (light to dark), remember that IR light is invisible to us.
if (state2>state1){
currentTime = micros(); // Get the arduino time in microseconds
diffTime = currentTime - prevTime; // calculate the time diff from the last meet-up
rps = 1000000/diffTime; // calculate how many rev per second, good to know
rpm = 60000000/diffTime; // calculate how many rev per minute
unsigned long currentMillis = millis();
// print to serial at every interval - defined at the variables declaration
if(currentMillis - prevMillis > interval){ // see if now already an interval long
prevMillis = currentMillis;
Serial.print(rps); Serial.print(" rps "); Serial.print(rpm); Serial.println(" rpm");
}
prevTime = currentTime;
}
state2 = state1;
}
{
Input = analogRead(rpm);
myPID.Compute();
analogWrite(9, Output);
}
/*
//only for testing to determine the sensorthreshold value
delay(500);
Serial.println(sensorvalue);
*/
}
kalai14:
Can sir show me how to attach PID control in the coding.
There is no need to use the word "sir". The word "you" or my name "Robin" will be fine.
In my short program the potentiometer is used directly to control the PWM value and hence the speed of the motor.
To work with PID the potentiometer should be used to change the value of Setpoint and the value of revDuration should be used as the other input for the PID calculation. Then the output of the PID calculation will be the value for PWM.
To work with PID the potentiometer should be used to change the value of Setpoint and the value of revDuration should be used as the other input for the PID calculation. Then the output of the PID calculation will be the value for PWM.
I want to control the value of PMW through Arduino coding and the PID too. What if i set the Setpoint value same as my PMW value. Will it work to control the speed ?
kalai14:
What if i set the Setpoint value same as my PMW value. Will it work to control the speed ?
That question leads me to think that you don't understand how PID works.
If you already know the PWM value so you can put it in the Setpoint then what would be the value of the PID calculations?
The idea underlying PID is that you have a Setpoint representing the speed you want to achieve, and also a measurement of the actual speed which is updated frequently. The PID calculations continually compare the actual speed with the desired speed and try to adjust the motor power so as to keep the speed constant.
You set the PWM value for pin 9 to the garbage value that Compute() calculated (based on complete nonsense as input), then loop() ends. Then, you set the PWM value of the ENA pin to 150.
int ENA = 9; // PWM DC motor pin
So, nanoseconds after you change the PWM value of pin 9, you set the PWM value back to 150.
It's no wonder that your motor never changes speed.
Where is the gnd and 5V connection between the Arduino and the 298 board.
Where is the power supply for the motor driver.
In the actual wiring i supplied 12V to the motor driver and the output 5V supplied back to Arduino and ground for both has been looped together. I did not drew in the diagram and sorry for that.
What is the IR device, link to specs/data?
What are you using as an IR source to aim at the IR device?
IR device input signal in connected to A0 in Arduino. I bought it through online so i do not know about the specs of the IR sensor.
The idea underlying PID is that you have a Setpoint representing the speed you want to achieve, and also a measurement of the actual speed which is updated frequently. The PID calculations continually compare the actual speed with the desired speed and try to adjust the motor power so as to keep the speed constant.
I need to study about how PID works before i do the coding part. I am sorry for that. The idea was to set a PWM value for the motor then provide feedback through IR Sensor to achieve the actual PWM signal set in the coding using PID