Example Code for Arduino-PID Speed Control
This tutorial demonstrates how to drive a DC motor using the L298P DC motor driver board, with a PID control algorithm applied to regulate the motor speed.
Hardware Preparation
- DFRduino Romeo‐All in one Controller (or similar) x 1
- 6V Power Supply x 1
- Jumper wires
- L298P DC motor drive board x 1
Software Preparation
Wiring Diagram
Motor PID Wiring (correspond to example2)
Just connect the positive and the negative to M1 and remain other parts as the same, and download example2.
Other Preparation Work
In this tutorial, D2 and D3 are selected, D2 is the interrupt pin and D3 is the signal input pin.
In practice, we just need to ensure one interrupt pin, and the other pin can be self-defined (see master of the interrupt pin in the figure below)
Notcie: attachInterrupt()
For example, if you want to use interrupt pin 0 (interrupt 0) on UNO, you can connect the number 2 digital pin (D2); With Interrupt Pin 1 (Interrupt 1), you can connect number 3 digital pin (D3).
Download and install the Arduino PID Library.
Sample Code
/*!
* @file FIT052X.ino
* @brief Metal DC Motor Encoder - 6V
* @n Drive the DC motor via the L298P DC motor drive board.
* @n The PID algorithm controls the speed of the motor.
* @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
* @license The MIT License (MIT)
* @author DFRobot
* @version V1.0
* @date 2023-08-03
*/
//The sample code for driving one way motor encoder
#include <PID_v1.h>
const byte encoder0pinA = 2;//A pin -> The interrupt pin 0
const byte encoder0pinB = 3;//B pin -> The digital pin 3
int E_left = 5; //Connect the enabling port of the L298P DC motor drive shield to digital port 5
int M_left = 4; //Connect the turning port of the L298P DC motor drive shield to digital port 4
byte encoder0PinALast;
double duration, abs_duration;//The number of the pulses
boolean Direction;//The rotation direction
boolean result;
double val_output;//Provide the PWM output value to motor
double Setpoint;
double Kp = 0.6, Ki = 5, Kd = 0;
PID myPID(&abs_duration, &val_output, &Setpoint, Kp, Ki, Kd, DIRECT);
void setup()
{
Serial.begin(9600);//Initialize the serial port
pinMode(M_left, OUTPUT); //Set the control port of the L298P DC motor drive shield to output mode
pinMode(E_left, OUTPUT);
Setpoint = 80; //Set PID output value
myPID.SetMode(AUTOMATIC);//Set PID to automatic mode
myPID.SetSampleTime(100);//Set the PID sampling frequency to 100ms
EncoderInit();//Initialize the module
}
void loop()
{
advance();//Motor rotates clockwise
abs_duration = abs(duration);
result = myPID.Compute();//The return value is 1 after PID conversion
if (result) {
Serial.print("Pluse: ");
Serial.println(duration);
duration = 0; //Clear count value and waits for the next count
}
}
void EncoderInit()
{
Direction = true;//default -> Forward
pinMode(encoder0pinB, INPUT);
attachInterrupt(0, wheelSpeed, CHANGE);
}
void wheelSpeed()
{
int Lstate = digitalRead(encoder0pinA);
if ((encoder0PinALast == LOW) && Lstate == HIGH) {
int val = digitalRead(encoder0pinB);
if (val == LOW && Direction) {
Direction = false; //Reverse
} else if (val == HIGH && !Direction) {
Direction = true; //Forward
}
}
encoder0PinALast = Lstate;
if (!Direction) duration++;
else duration--;
}
void advance()//Motor rotates clockwise
{
digitalWrite(M_left, LOW);
analogWrite(E_left, val_output);
}
void back()//Motor rotates counterclockwise
{
digitalWrite(M_left, HIGH);
analogWrite(E_left, val_output);
}
void Stop()//Motor stops
{
digitalWrite(E_left, LOW);
}
Result
Because the program sets a PID value of 80, the stable speed of the motor is around 80.
When external forces (such as the driving voltage change of the motor, the resistance of the motor increased, etc.) force the speed to change, the program adjust the speed to about 80 through the PWM.
For example, increase the motor drive voltage, the motor speed will briefly rise to 80. Reduce the motor drive voltage, the motor speed will temporarily drop, then rise to 80.
Was this article helpful?
