In this instruction, I will show how to control motor speed with PID algorithm, by Arduino UNO
With PID control, speed of motor can be archived exactly. This instruction mainly introduces about making program in Arduino UNO, and program in Computer (Visual Studio) to control motor speed by PID algorithm
Arduino UNO is used to store program motor control, PID algorithm, communicating with computer through COM Port Computer will have HMI made by Visual Studio to communicate with Arduino. HMI will show motor speed graph, change motor speed setting, and PID gain
Let's go in detail
Step 1: Hardware and Software needed
To make this project, you will need following hardware:
1. Motor with encoder https://amzn.to/2RHsCRj
2. H-bridge L298 https://amzn.to/2QS2FeI
3. Arduino UNO https://amzn.to/2P58O7s
4. Motor base http://bit.ly/2DZJOZV
The motor with encoder, you can choose any DC motor but you need to know how many pulse of encoder per revolution. In case you don't know, you can make simple program with Arduino, then rotate motor shaft to know how many pulse of encoder per revolution. In my case, it is 200 pulses per revolution.
About software, you will need Arduino IDE to program Arduino UNO, and Visual Studio to make HMI on computer In my case, I use Visual Studio 2008, you can use newest version if you can
Step 2: Hardware connection
Make circuit like this diagram, it's easy for us: encoder from motor will connect to pin 2 and 3; H-bridge is used to control motor speed, then pin 4, 5 and 6 will connect to H-bridge. And, output of H-bridge is connected to motor
Then install the circuit to motor base like picture
Step 3: Arduino Code
Arduino code will do:
(1) Calculate motor speed
(2) Send motor speed to Computer
(3) Calculate PWM pulse (base on PID algorithm)
(4) Push result of PWM to H-brigde
String mySt = "";
char myChar;
boolean stringComplete = false; // whether the string is complete
boolean motor_start = false;
const byte pin_a = 2; //for encoder pulse A
const byte pin_b = 3; //for encoder pulse B
const byte pin_fwd = 4; //for H-bridge: run motor forward
const byte pin_bwd = 5; //for H-bridge: run motor backward
const byte pin_pwm = 6; //for H-bridge: motor speed
int encoder = 0;
int m_direction = 0;
int sv_speed = 100; //this value is 0~255
double pv_speed = 0;
double set_speed = 0;
double e_speed = 0; //error of speed = set_speed - pv_speed
double e_speed_pre = 0; //last error of speed
double e_speed_sum = 0; //sum error of speed
double pwm_pulse = 0; //this value is 0~255
double kp = 0;
double ki = 0;
double kd = 0;
int timer1_counter; //for timer
int i=0;
void setup() {
pinMode(pin_a,INPUT_PULLUP);
pinMode(pin_b,INPUT_PULLUP);
pinMode(pin_fwd,OUTPUT);
pinMode(pin_bwd,OUTPUT);
pinMode(pin_pwm,OUTPUT);
attachInterrupt(digitalPinToInterrupt(pin_a), detect_a, RISING);
// start serial port at 9600 bps:
Serial.begin(9600);
//--------------------------timer setup
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
timer1_counter = 59286; // preload timer 65536-16MHz/256/2Hz (34286 for 0.5sec) (59286 for 0.1sec)
TCNT1 = timer1_counter; // preload timer
TCCR1B |= (1 << CS12); // 256 prescaler
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt
interrupts(); // enable all interrupts
//--------------------------timer setup
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
analogWrite(pin_pwm,0); //stop motor
digitalWrite(pin_fwd,0); //stop motor
digitalWrite(pin_bwd,0); //stop motor
}
void loop() {
if (stringComplete) {
// clear the string when COM receiving is completed
mySt = ""; //note: in code below, mySt will not become blank, mySt is blank until '\n' is received
stringComplete = false;
}
//receive command from Visual Studio
if (mySt.substring(0,8) == "vs_start"){
digitalWrite(pin_fwd,1); //run motor run forward
digitalWrite(pin_bwd,0);
motor_start = true;
}
if (mySt.substring(0,7) == "vs_stop"){
digitalWrite(pin_fwd,0);
digitalWrite(pin_bwd,0); //stop motor
motor_start = false;
}
if (mySt.substring(0,12) == "vs_set_speed"){
set_speed = mySt.substring(12,mySt.length()).toFloat(); //get string after set_speed
}
if (mySt.substring(0,5) == "vs_kp"){
kp = mySt.substring(5,mySt.length()).toFloat(); //get string after vs_kp
}
if (mySt.substring(0,5) == "vs_ki"){
ki = mySt.substring(5,mySt.length()).toFloat(); //get string after vs_ki
}
if (mySt.substring(0,5) == "vs_kd"){
kd = mySt.substring(5,mySt.length()).toFloat(); //get string after vs_kd
}
}
void detect_a() {
encoder+=1; //increasing encoder at new pulse
m_direction = digitalRead(pin_b); //read direction of motor
}
ISR(TIMER1_OVF_vect) // interrupt service routine - tick every 0.1sec
{
TCNT1 = timer1_counter; // set timer
pv_speed = 600.0*(encoder/200.0)/0.1; //calculate motor speed, unit is rpm
encoder=0;
//print out speed
if (Serial.available() <= 0) {
Serial.print("speed");
Serial.println(pv_speed); //Print speed (rpm) value to Visual Studio
}
//PID program
if (motor_start){
e_speed = set_speed - pv_speed;
pwm_pulse = e_speed*kp + e_speed_sum*ki + (e_speed - e_speed_pre)*kd;
e_speed_pre = e_speed; //save last (previous) error
e_speed_sum += e_speed; //sum of error
if (e_speed_sum >4000) e_speed_sum = 4000;
if (e_speed_sum <-4000) e_speed_sum = -4000;
}
else{
e_speed = 0;
e_speed_pre = 0;
e_speed_sum = 0;
pwm_pulse = 0;
}
//update new speed
if (pwm_pulse <255 & pwm_pulse >0){
analogWrite(pin_pwm,pwm_pulse); //set motor speed
}
else{
if (pwm_pulse>255){
analogWrite(pin_pwm,255);
}
else{
analogWrite(pin_pwm,0);
}
}
}
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
if (inChar != '\n') {
mySt += inChar;
}
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}
Step 4. Code works at Computer
Visual Studio 2008 is used to make HMI program, in which:
(1) Send speed setting to Arduino
(2) Send PID gain to Arduino
(3) Receive motor speed, show on graph
Note that, communication between Arduino and Visual Studio by COM communication
The code can be download at http://bit.ly/2PqlYvQ
Watch video to see how it works
Will it work on arduino uno
ReplyDeleteSure!
Deleteso we just didn't need the UART PCB and we don't need to edit arduino code even when using arduino uno?
Deletesorry to bother you but i really need a fast answer
Right, Arduino UNO already had UART PCB inside. When Arduino UNO connect to Computer via USB Port, an COM Port will be shown -> use this COM Port No. to communicate between Arduino UNO and Computer.
DeleteAbout the code, i try to compile for UNO, it run perfectly. Let's try it!
Can you give me scematick arduino-motor?
DeleteHi, schematic is from this post https://www.engineer2you.com/2016/12/arduino-motor-speed-control-pwm.html
DeleteHow can i try to input the value of speed, kp, ki, kd by using serial monitor in arduino program?
ReplyDeletethank you
Fungkyking01@gmail.com
Hi. Unfortunately i already removed this model (motor, circuit,...) -> can't make project again as your mention.
DeleteYou should find an example to read data input from serial port -> then, import parameters (kP, kI, kD) to formular. It's not difficult, let's do it
Bro Can you kindly Provide the whole circuit diagram. its quite confusing which connection goes where. thnx in advance
ReplyDeletePlease come to thà link to see connection
ReplyDeletehttp://engineer2you.blogspot.com/2016/12/arduino-motor-speed-control-pwm.html?m=1
Bro I followed all the steps you mentioned and made the project with Arduino Uno. The problem I get is that the PID is not working, the motor keeps on rotating with a constant speed of 530 RPM and when I apply some load to the motor the speed reduces and does not go back to 538 RPM. Also I can't send commands to arduino. like i want the motor to rotate with a speed for 700 RPM and 300 RPM for example, it does not work when i press the send button on HMI.
ReplyDeleteHi,
Delete(1) First step is make sure you can send command (and convert it to integer) into Arduino. You can search on web this kind of project, or see here http://engineer2you.blogspot.com/2016/12/arduino-uart-communication.html
(2) Tuning PID parameter is not easy. Each motor will have each parameter. First tuning, you should make kP, kI some small value, kD=0, then see motor reaction. Then gradually increase or decrease kP, kI. Normally, no need kD.
Is there an equivalent motor that can be used with this system, it is very difficult to find the one you used.
ReplyDeleteYou can use any DC motor, then find kP kI kD for it
DeleteHi this is one s brilliant!! I'm want to design kind of this but slightly different..
ReplyDeleteThere is LCD or 7 segment using the rotary encoder rpm 0-8000 per 1 rpm changes, first we need to a rpm then once after pressing start arduino need to rpm of the motor
Can you suggest me any enocder motor up to 8000rpm n how to control the motor?
Help me pls
Hi, There's rearly motor with encoder 8000 ppr (pulse per round). If you need 8000ppr encoder, you have to use external encoder, connect to motor shaft by coupling. I was wondering if what application you need 8000ppr encoder? Could you share? We will make it together (because i'm free now haha)
DeleteI want to draw Set Speed in chart with series 2 is color Red, Can you help me
ReplyDeletePlease try yourself in Visual Studio. I think it's not difficult.
DeleteSet Speed in Textbox I run Series2 but i don't know convert Text
Delete/this->chart1->Series["Series2"]->Points->AddXY(i,System::Convert::ToDouble(textBox1)); i++;
Delete// this->chart1->ChartAreas["ChartArea1"]->AxisX->Minimum=i;
Thank you: i did convert textbox1->text ok
DeleteCan you please guide me about the specifications of motor with encoder? And also where to buy it from in INDIA?
ReplyDeleteHi, you can buy any DC motor which has encoder inside.
DeleteHey , can you explain to me how to convert speed RPM to PWM ?
ReplyDeleteHi, i don't know calculation to convert speed rpm to PWM. This calculation is difficult, depends on characteristic of motor, load.
DeleteInstead of calculation speed to PWM, we use PID algorithm. How it works?
Let's think, PWM=0% -> speed is 0rpm; PWM=100% -> speed is max, let's say 2000rpm
PID will calculate PWM depend on error of speed feedback and speed setting -> output to PWM pulse to reach setting speed.
Hope i can help you.
Hi
ReplyDeletethanks for sharing this brilliant works . I have couples of question , first what version of visual studio you use and if I have motor with 2 wires only and it's gear motor , do u think that i still need encoder cuz I want to control the speed by using ur way in where if I need 450 rpm and the motor should rotate the desired speed , Do u think my motor able to do , here is my motor characters https://www.alibaba.com/product-detail/VTV-24v-dc-motor-1500-rpm_60645604396.html?spm=a2700.7724838.2017115.195.2bc1680aS46x0Z
thank you so much
Hi,
DeleteI use Arduino 1.6.11, but you can use latest version -> it's no problem
Your suggested motor has no encoder -> impossible to control speed. Without encoder, how could we know speed? You should choose another motor with encoder.
Thanks for visit my blog.
This comment has been removed by the author.
ReplyDeletehow i can calculate the parameter of dc motor (j.B.L.)?
ReplyDelete2-Are you can send me code of pid controller without using parameters(j.B.L)?
Hi, i don't calculate parameter of DC Motor
DeleteThe code of PID controller (without using parameter DC Motor) is in my blog. Please read it all.
Thanks for visit.
ok..
ReplyDeletebut are you have any away to calculate parameter of dc by matlab ?
Hi, i know your mean: using calculated parameter to make PID parameter. Unfortunately, this project is not aimed to do that, this just tuned PID by experience and make it run.
Deletethank very mach
ReplyDeleteHola, ill be making this the next week,i hope ull be here for my questions,and i want to thank you for sharing this project with the internet :)
ReplyDeleteSure. Lets keep in touch here
Deletei didnt find near me the needed equipments, so can i use the same concept with Arduino UNO +ESC 30A + A brushless motor ?
DeleteSure, but you must have a way to let Arduino UNO know speed of brushless motor.
DeleteOkey, do you have any suggestions how i do that?
DeletePlease search on Google the way how to read speed of brushless motor
Deletegood morning, i have the next problem Excepción no controlada del tipo 'System.FormatException' en mscorlib.dll could you help me?, please
ReplyDeleteHi, please make program with Visual Studio step by step, then try to find where error comes from
Deletehello,
ReplyDeletewhat is 60 , 200.0, and 0.1 in the following line ?
pv_speed = 60.0*(encoder/200.0)/0.1;
Hi, 200 is encoder pulse for 1 round; 0.1 is sample time (this case is 0.1sec)
Deleteencoder/200 -> we will know how many round the motor is turned
(encoder/200)/0.1 -> round per 0.1sec
600*(encoder/200)/0.1 -> round per 60 sec -> round per minute
haha, if so, above code is wrong, the calculation should be:
pv_speed = 600.0*(encoder/200.0)/0.1
Thanks for your comment.
Thank you very much for your quick reply.. This Project is Awesome. It is very clear even for those don't understand the theory behind PID.
Deletein the arduino code pv_speed per 0.1s calculation is multiplied by 60 so that should be 600 in order to have the rpm value right.
big thumbs up for the useful post.
Thanks for your visit.
Deletewhen i run the visual studio code give me this error.
ReplyDeleteError 3 error TRK0005: Failed to locate: "rc.exe". The system cannot find the file specified. E:\test_14_2\New folder\WindowsFormsApplication3\WindowsFormsApplication3\TRACKER WindowsFormsApplication3
i'm not sure this error. So please paste the code into your Visual Studio and try to compile it.
DeleteHi, where did you call the function "serialEvent" in the Arduino code.
ReplyDeleteHi, please visit this link to know about function "serialEvent"
Deletehttps://www.engineer2you.com/2016/12/arduino-serial-communication-visual.html
Sir
ReplyDeleteif (e_speed_sum >4000) e_speed_sum = 4000;
if (e_speed_sum <-4000) e_speed_sum = -4000;
what above lines in code are doing???is it assigning rated shaft speed if it exceeds rated speed value???
you're right. this prevents motor reaching rated speed in case of wrong PID parameter.
Deleteso if my motor rated speed is 225 , then i have use 225 in place of 4000 right???what -4000 indicates , reverse direction of motor???
DeleteYes. Please replace it with your max speed.
DeleteIf i make this kind of KIT with 50$ (motor, H-bridge, Arduino UNO, mechanical assembly parts), ship over the world. Will you purchase with pre-pay by Paypal? How to you think?
can please explain why you selected 2,3,4,5,6 pins???if i am using arduino uno can it be ok same pins ???can u give description why you used those pins.
ReplyDeleteHi, please visit this link, you will understand function of pin 2 ~ 6, then you can replace it by UNO
Deletehttps://www.engineer2you.com/2016/12/arduino-motor-speed-control-pwm.html
sir pin 4 of H-bridge, if high then motor rotates in forward direction correct or not???same goes with pin5???sir ardiuno it is given IN1,IN2,IN3,IN4 as inputs for two motors and two enable pins En A ,En B .so pin 4 and 5 of H-BRIDGE IS EQUIVALENT TO IN1 AND IN2???
ReplyDeleteYes, Arduino Pin 4&5 to H-bridge IN1&2
DeleteArduino Pin6 to H-bridge ENA
Just try it, you will get it :)
Hi, i have just update picture of connection between Arduino and H-bridge on Step1. Please take a look.
Deleteserial.available()<=0 means what???data not available???can you justify this line of your code.
ReplyDeletesir for me current speed in visual studio not displaying,what shall i do???
ReplyDeleteNo waveform is coming but motor working fine.i dont know motor parameters,i am just trying z-n tuning method.
Hi, firstly, you have to make sure that Arduino can communicate to Visual Studio by COM communication. Please come here
Deletehttps://www.engineer2you.com/2016/12/arduino-serial-communication-visual.html
After confident about communication COM between Arduino and Studio, you will be able to show motor speed.
can i control speed without encoder by estimation ??
ReplyDeleteHI, if by estimation, you can control it by PWM, please visit this link
Deletehttps://www.engineer2you.com/2016/12/arduino-motor-speed-control-pwm.html
Great Article
ReplyDeleteInternet of Things Final Year Project
Final Year Project Centers in Chennai
Dear sir, I am using the motor shield l293d in my project ,thus istead of using pin 2 for encoder A, I use pin 19 which is also an interrupt pin. However the output pwm_pulse is always 0 even with any kp ki kd values. Then I try to divide the code into mutilple parts and try to see if it work properly. At first I tested the encoder function, it only work when i hidden the timer setup. Then I add the ISR() function and try to print out the pv_speed, but at this point I only got the 0 value on the monitor. so i guess the problem is from here. Could you please suggest me any idea to fix the problem ? thank you in advance.
ReplyDeleteHi, you can only use Pin 2 or Pin 3 (where is used for INT0 or INT1) for encoder A. Please try again with each section of code, you will understand. Thank you.
DeleteElectric motor repair can take many forms, ac motor repair depending on what kind of electric motor you have and the nature of its use in your business.
ReplyDeleteHi,
ReplyDeleteI want to use MATLAB Guide instead of Visual Studio, may I get the code for MATLAB Guide.
For a fraction of that cost, you can find a reconditioned used motor that will outlive any car you put it in. Actually, car dealer F&I products I've known of some that have outlived 2 cars.
ReplyDeletessssss
ReplyDeleteIs it possible to have the datasheet of the motor used? in the video, which is the value in sec of the x axis? whithout datasheet, how I can determine that the encoder gives 200 counts per rounds. Which is the raise time of the motor, otherwise how you can choose a period of .1 sec for the PID control? In particolar, for the motor that you cited on AMAZON, there is no datasheet available. Thanks for your tie and answer.
ReplyDelete