Arduino - Motor speed control pwm

This article will show how to control motor speed by PWM



Hardware needed:
1. Motor with encoder
2. H-bridge L298N
3. Arduino pro mini
1. Motor with encoder
2. H-Bridge L298N
3. Arduino Pro Mini

















Connected them together:
Result bellow looks not perfect in shape, but it works well
How to connect them?

(1) Connect encoder to Arduino
This encoder has pulse A, B -> connect to Arduino, don't forget connect power for it. So there will be totally 4 wires connected from motor encoder to Arduino.
     Arduino pin 2 <-> Encoder pulse A
     Arduino pin 3 <-> Encoder pulse B
     Arduino VCC <-> Encoder power
     Arduino GND <-> Encoder GND




(2) Connect to H-bridge module
H-bridge normally is used to control motor speed, direction -> let's google it to see how it works. In this article, H-bridge uses chip L298N.
This module will have direction signal (3 wires): 1 for "Forward", 1 for "Backward", 1 for "Enable". Arduino will output signal to direction signal to control direction of motor (through "Forward", "Backward" signal), to control speed of motor (through "Enable" signal):
     Arduino pin 4 <-> H-bridge "forward"
     Arduino pin 5 <-> H-bridge "backward"
     Arduino pin 6 <-> H-bridge "Enable"
Of course the H-bridge PCB will have output to Motor, this will be connected to Motor. Also power source for it, this power is used for chip L298N, also motor. This case, it is about 12VDC.
Note that, there is another cable: GND (ground) cable from Arduino -> it needs to be connected for sending signal from Arduino to H-bridge PCB (this GND cable is used to make the base for signal from Arduino)


Code works:

motor_speed (part 1)
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;
int timer1_counter; //for timer

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 = 34286;   // preload timer 65536-16MHz/256/2Hz

  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
  }

}

Attachments

In part 1, variables are declared. Next is set pulse A, pulse B of encoder as input; output for "forward", "backward", "PWM" signal
Let's go inside meaning:
attachInterrupt(digitalPinToInterrupt(pin_a), detect_a, RISING);
This code is used to detect rising edge of pulse A encoder.
Encoder of motor is kind of disk, compacted with IR sensor, then output pulse A and B which is 90dg oppositely. In case run forward, rising edge of pulse A, B will be at 0 logic. In case run backward, rising edge of pulse A, B will be at 1 logic. By this, motor direction can be detected.
In the code, every time at rising edge of pulse A, an interrupt routine (name: detect_a()) will be called. In part 2 of code, sum of encoder will be calculated, and direction of motor also detected.
Next of the code is declare about UART communication -> this will be used to print out result for User
Next is timer set up -> in sort, this timer is configured at 0.5sec -> means that every 0.5sec, timer1 is ticked -> program will come to timer1 interrupt routine (in part 2). Timer1 is used to calculated motor speed

motor_speed (part 2)
void loop() {
    digitalWrite(pin_fwd,0);        //run motor backward
    digitalWrite(pin_bwd,1);        //run motor backward
    analogWrite(pin_pwm,sv_speed);  //set motor speed
    Serial.print("speed (rpm) is : ");
    Serial.print(pv_speed);         //Print speed value to Computer
    Serial.print("  --  ");
    Serial.print("Direction = ");
    Serial.println(m_direction);
    delay(500);
}

void detect_a() {
  encoder+=1;
  m_direction = digitalRead(pin_b);
}
ISR(TIMER1_OVF_vect)        // interrupt service routine - tick every 0.5sec
{
  TCNT1 = timer1_counter;   // set timer
  pv_speed = 60*(encoder/200.0)/0.5;
  encoder=0;
}

Attachments


 Part 2 is continued of program.
At first, motor will be set to run backward. Then set PWM pulse to control motor speed (Google it to see how PWM control speed):
 analogWrite(pin_pwm,sv_speed);
In this case, PWM pulse width is controlled by variable sv_speed, now sv_speed=100 of 255 (max) ~ 39%
Next of code is print result to UART port
Let's see 2 interrupt routine:
Encoder interrupt: as explain in part 1, every time at rising edge of encoder pulse A, this routine is called -> sum encoder, and read motor direction
Interrupt timer1 routine: every 0.5s, this routine is called -> calculate motor speed. In this case, motor encoder 1 revolution has 200 pulse.

Joint 2 parts of code. Compile it and download to Arduino -> Open serial port in Arduino IDE to see result (Tool > Serial Monitor).
The total code can be downloaded here (Google share)

Result:

At first, motor speed is 0 rpm (we turn off 12VDC power for H-bridge)
Then, 12VDC power is supplied for H-bridge, motor is running, speed is increasing
If motor shaft is touched (has some load), motor speed will decreased.




22 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Hy i interest with your article, i want ask can you describe how equation to set timer to every ms we want? Example i want run every 0.1 ms or 0.5 ms , thanks before

    ReplyDelete
  3. Hy i interest with your article, i want ask can you describe how equation to set timer to every ms we want? Example i want run every 0.1 ms or 0.5 ms , thanks before

    ReplyDelete
    Replies
    1. Hi, please google it. It is easy to search it on Internet.

      Delete
  4. Can you please guide me about the specifications of motor with encoder? And also where to buy it from in INDIA?

    ReplyDelete
    Replies
    1. Hi, you can buy any DC motor which integrated encoder inside.

      Delete
  5. hi, i'm newbie and little bit curious here, this line is for controlling PWM, right ?

    "int sv_speed = 100; //this value is 0~255"

    what if i change the value to the max (255), what will happen ? what's the impact for the motor speed and the PID tuning ? Thank You

    ReplyDelete
    Replies
    1. if max value (255), motor will rotate max speed at present power supply for motor (H-bridge), just like you connect power to motor directly. This code doesn't contain PID code, so it doesn't impact to PID tuning.

      Delete
    2. wow kudos for your answer, if i wanna use potentiometer A0 to varying the speed of the motor, is't possible? if yes, where did i must put the code analogRead(); and analogWrite(A0); of potentiometer ? big thanks

      Delete
    3. Yes, you can do it. Just add the code into "void loop()":
      sv_speed = analogRead(A0);

      That's all. Let's try to see if it works.

      Delete
  6. sir i am using SPG30E-20K DC Geared motor with encoder inside it.It has maximum RPM=225,810 counts per main shaft revolution,3 pulses per rear shaft revolution, single channel output.Sir can u tell me where the changes will come in the above code for this motor?whether it is only rpm calculation or any other code part will change?thank u in advance sir.....thank u so much for ur work.

    ReplyDelete
    Replies
    1. https://robu.in/product/dc-geared-motor-with-encoder-185rpm/

      sir my motor description given above.thank u sir

      Delete
  7. sir i am using SPG30E-20K DC Geared motor with encoder.Rating 12v,225rpm.Encoder details:60 counts per main shaft revolution for 1:20 geared motor.So sir ,can u tell me below calculation is correct or not
    RPM =60*(encoder/60)/0.1

    ReplyDelete
    Replies
    1. Hi, meaning of calculation (in case your motor 60 pulse per revolution) is:
      encoder/60: calculate how many revolution which motor rotated
      (encoder/60)/0.1: calculate how many revolution per second, unit will be rps (this case, your timer interrupt MUST be 0.1sec)
      60*(encoder/60)/0.1: calcualte how many revolution per second, unit will be rpm

      I hope you can get it :)

      Delete
    2. Thank you sir.i am happy for your quick response,thank you so much.

      Delete
  8. Hi sir,
    I am doing a project on the comparison of speed by using fuzzy and PID logics. How to do in a simpler way using Arduino.need to determine speed , no of turns,etc. And more parameters related to DC motor . So that I can compare the better performance logic control

    ReplyDelete
    Replies
    1. I didn't get your mean so much. You can visit another article for PID motor speed control by Arduino https://www.engineer2you.com/2016/12/arduino-motor-pid-speed-control.html

      Delete
    2. The topic is comparing the two logic controllers using DC motor. Logic controllers are fuzzy logic and PID. I need to practically do this one. With PID I need to control it's speed. Also I need to draw a graph between rpm or speed versus tim in both the cases.

      Delete
    3. Hi, here is my project to control motor speed with PID (this project also draw speed graph in rpm vs time) https://www.youtube.com/watch?v=QNCWW4TX4Gg

      Delete
  9. Hi, did you consider the motor mathematical model in your program?

    ReplyDelete
    Replies
    1. No, i just push out PWM to make motor run, then count motor speed based on timer interrupt

      Delete