PID DC brushed motor control

Help me by sharing this post


IN this tutorial we will see how to control one axis but using BRUSHED DC MOTORS. Usually CNC axis will move using stepper motors in an open loop control. Here we will see an example of close loop control with an optic encoder as feedback. Why do this? well, for bigger motors, the price of stepper motors and drivers could get very high. Using DC brushed motors with a gear box and close loop control could get cheaper. Lets see how to do this.

PART 1 - What we need

I will make just only one axis. See full part list also here on this link. For that we need the parts below. The motor with the encoder in quadrature, the H bridge driver, the Arduino with a potentiometer and the rest of components. For the motor you could get only the motor and then make your own gear system or buy directly the motor witha gear box. See the scheamtic for all the connections.

We need:
Arduino PID CNC axis brushed DC motor

I've mounted everything on a plywood baord. We also need some M3 screws for that or maybe some glue. Some lubrificant for the rods and lead screw also would be good.

PART 2 - Schematic

Make the connections as below. Supply a different connection to the H bridge with enough current. Remember to share GND with all the modules. The End stop swithc will need a pullup and give a low pulse when the siwthc is pressed, otherwise you will need to change that in the code. The encoder needs 5V, GND and two encoder outputs.

Arduino schematic brushed DC PID motor control

PART 3 - Code

Copy the code from below or download it from the link. You will need to install the needed libraries. Go to the link below and find those libraries and install them to your Arduino IDE. Read all the lines in the code to understand more. The setpoint is given with the potentiometer but you could use Serial read for example and give precise values for the setpoint and see the results.

//Include the libraries we need
#include <PinChangeInterrupt.h>
#include <PinChangeInterruptBoards.h>
#include <PinChangeInterruptPins.h>
#include <PinChangeInterruptSettings.h>
#include <TimerOne.h>                          // Timer one interrupts

/////////////////////DEFINE PID constants/////////////////////
int kp = 2, ki = 0.01, kd = 0.02;

int input, output, setpoint;
int iTerm = 0, lastInput = 0, dInput = 0, error = 0;
int outMin = -255, outMax = 255;
int sampleTime = 10;                                //This values is is milliseconds
volatile long encoderPos = 0;

////////////////////Define the pins we use////////////////////
#define Encoder_A      2                                    // Quadrature encoder A pin
#define Encoder_B      8                                    // Quadrature encoder B pin
#define Motor_CW       11                                   // PWM outputs to L298N H bridge motor driver module
#define Motor_CCW      3
#define led            13
#define END_stop       4

void setup(void)
  pinMode(Encoder_A, INPUT);                                // quadrature encoder input A
  pinMode(Encoder_B, INPUT);                                // quadrature encoder input B
  pinMode(END_stop, INPUT);                                 // Input from the end stop switch
  pinMode(led, OUTPUT);
  attachPCINT(digitalPinToPCINT(Encoder_A), encoder, FALLING);  // We update encoder position each falling edge detected in the interrumption
  TCCR2B = TCCR2B & 0b11111000 | 1;                             // set 31Kh PWM to prevent motor whine (timer 2)
  Timer1.initialize(sampleTime * 1000);                         // setup timer 1
  Serial.begin(115200);                                         //Just for debugging if you want to print values
    analogWrite(Motor_CW, 0);                                   // Rotate the motor CCW
    analogWrite(Motor_CCW, 255);
  analogWrite(Motor_CW, 0);                                     // Stop the motor
  analogWrite(Motor_CCW, 0);

void Compute()
  setpoint = map(analogRead(0),0,1024,1024,0) * 110;            // setpoint position is made with a potentiometer but could be given by serial monitor or other...
  input = encoderPos;                                           // we get the data from the encoder interrumption
  error = setpoint - input;
  iTerm += ki * error * sampleTime;
  if (iTerm > outMax) iTerm = outMax;                           // prevent that the I term from PID gets too big
  else if (iTerm < outMin) iTerm = outMin;
  dInput = (input - lastInput) / sampleTime;
  output = kp * error + iTerm - kd * dInput;                    // The PID output is the sum of P I and D values
  if (output > outMax) output = outMax;                         // limit output to 0 and 255 for the analog write
  else if (output < outMin) output = outMin;          
  lastInput = input;                                            //Remember to save the last input value for the next loop
  pwmOut(output);                                               //Change the analog write for the motor control

void pwmOut(int out) {                                          // to H-Bridge board
  if (out > 0) {
    analogWrite(Motor_CW, out);                                 // Rotate the motor CW
    analogWrite(Motor_CCW, 0);
  else {
    analogWrite(Motor_CW, 0);
    analogWrite(Motor_CCW, abs(out));                           // Rotate the motor CCW

void encoder()  {                                     // pulse and direction, direct port reading to save cycles
  if (PINB & 0b00000001)    encoderPos++;             // if(digitalRead(encodPinB1)==HIGH)   count ++; //We increase steps by 1
  else                      encoderPos--;             // if (digitalRead(encodPinB1)==LOW)   count --; //We decrease steps by 1

void loop(void)
  digitalWrite(led, !digitalRead(led));               // blink led or do something else...

PART 4 - Video

See the video for more information and see what options you have for the encoder, how to detect the pulses and so on. I hope you will like this project. Comment below and help the community. COnsider supporting me on PATREON.

Help me by sharing this post


DC motor PID
page 1/1

PCBWAY PCB service

PCBWAY PCB service