Adaptive PID Controller For DC Motor Speed Control

59 views (last 30 days)
I am developing a program to control the speed of a DC motor using an adaptive PID controller. As I am just getting started with this type of control, I would greatly appreciate it if anyone could share code, algorithms for simulation, or practical implementation examples of such a controller for my reference
  1 Comment
Sam Chak
Sam Chak on 1 Oct 2025 at 6:37
Hi @Mnh
Could you share the code for the DC motor model and the PID controller without the adaptive feature? The adaptive feature is not necessary to determine to what extent the motor can maintain its performance.

Sign in to comment.

Accepted Answer

Mathieu NOE
Mathieu NOE on 1 Oct 2025 at 16:07
hello
maybe this ?
clc
clearvars
% To control the speed of a DC motor using an adaptive PID controller in MATLAB, you can follow these steps. Below is an example implementation:
%
% Step 1: Define the DC Motor Model
% The DC motor can be modeled using its transfer function or state-space representation. For simplicity, we use a transfer function:
%
% ( J ): Moment of inertia
% ( b ): Damping coefficient
% ( K ): Motor constant
% ( R ): Resistance
% ( L ): Inductance
% Step 2: Implement Adaptive PID Controller
% An adaptive PID controller adjusts its parameters ((K_p), (K_i), (K_d)) dynamically based on system performance.
% Parameters of the DC motor
J = 0.01; % Moment of inertia
b = 0.1; % Damping coefficient
K = 0.01; % Motor constant
R = 1; % Resistance
L = 0.5; % Inductance
% Simulation parameters
dt = 0.01;
t = 0:dt:3; % Time vector
% Transfer function of the DC motor
num = K;
den = [(J*L) (J*R + L*b) (b*R + K^2)];
motor_tf = tf(num, den);
% discretization
[B,A] = c2dm(num,den,dt,'tustin');
% Initial PID parameters
Kpi = 100; Kii = 500; Kdi = 10;
%% init
desired_speed = 100; % Desired motor speed (rad/s)
actual_speed(1) = 0; % Initial speed
%% Adaptive PID control loop
% 1st sample
error(1) = desired_speed - 0 ; % Calculate error
error_int(1) = 0; % Calculate integral of error
error_der(1) = 0;% Calculate derivative of error
% PID controller output
u(1) = Kpi*error(1) + Kii*error_int(1) + Kdi*error_der(1);
% Simulate motor response
actual_speed(1) = B(1)*u(1);
% 2nd sample
error(2) = desired_speed - actual_speed(1); % Calculate error
error_int(2) = error_int(1) + 0.5*(error(2)+0)*dt; % Calculate integral of error
error_der(2) = (error(2)-error(1))/dt;% Calculate derivative of error
% PID controller output
u(2) = Kpi*error(2) + Kii*error_int(2) + Kdi*error_der(2);
% Simulate motor response
actual_speed(1) = B(1)*u(1);
actual_speed(2) = B(1)*u(2) + B(2)*u(1) + 0 - (A(2)*actual_speed(1) + 0 );
% 3rd sample and after
for i = 3:length(t)
error(i) = desired_speed - actual_speed(i-1); % Calculate error
error_int(i) = error_int(i-1) + 0.5*(error(i)+error(i-1))*dt; % Calculate integral of error
error_der(i) = (error(i)-error(i-1))/dt;% Calculate derivative of error
% Adaptive PID tuning
Kp = Kpi + 1*abs(error(i));
Ki = Kii + 1*abs(error(i));
Kd = Kdi + 0.01*abs(error(i));
% PID controller output
u(i) = Kp*error(i) + Ki*error_int(i) + Kd*error_der(i);
% Simulate motor response
actual_speed(i) = B(1)*u(i) + B(2)*u(i-1) + B(3)*u(i-2) - (A(2)*actual_speed(i-1) + A(3)*actual_speed(i-2));
end
%% Plot results
figure;
plot(t, actual_speed, 'b', 'LineWidth', 1.5); hold on;
yline(desired_speed, 'r--', 'LineWidth', 1.5);
xlabel('Time (s)');
ylabel('Motor Speed (rad/s)');
title('Adaptive PID Control of DC Motor');
legend('Actual Speed', 'Desired Speed');
grid on;
  9 Comments
Mnh
Mnh on 18 Oct 2025 at 16:41
@Mathieu NOE Thank you for your assistance; it has been quite helpful for my project. I am currently encountering some issues with the motor control algorithm in the real-world implementation. As you can see, at a speed of 5 rad/s, the plant does not accurately track the model and exhibits significant instability. This behavior similarly occurs within the speed range of 5–25 rad/s. When I set the speed to 30 rad/s, the motor initially overshoots and then experiences a severe drop in speed (sometimes even reaching zero or negative values, resulting in a brief reversal). Could you please provide me with some suggestions?
%% MRAS Adaptive PID (MIT rule) for DC Motor (MATLAB–Arduino Serial)
% Hardware:
% - Arduino UNO R3 + L298N + Encoder 334x34
% - The Arduino code transmits the motor speed (rad/s) via Serial communication
% - MATLAB performs the control computation and sends the PWM signal (0–255)
clc; clear; close all;
%% --- Serial Setup ---
port = "COM4"; baud = 115200;
s = serialport(port, baud);
configureTerminator(s, "LF");
flush(s);
disp('✅ Arduino Serial connection successful.');
pause(1);
%% --- MRAS-PID parameters ---
T = 0.05; % Control period (s)
setpoint = 5; % rad/s
am = 6.0; bm = 6.0; % Reference model
ym = 0;
gamma_p = 0.01; gamma_i = 0.003; gamma_d = 0.002;
norm_p = 0.08; norm_i = 0.02; norm_d = 0.05;
Kp = 1.8; Ki = 0.8; Kd = 0.05;
Kp_min=0.2; Kp_max=6.0; Ki_min=0; Ki_max=2.5; Kd_min=0; Kd_max=0.2;
I = 0; e_prev = 0; yp = 0; d_filt = 0;
deriv_alpha = 0.5; speed_alpha = 0.7;
PWM_MAX = 255; PWM_DEAD = 8; MAX_SPEED = 31;
%% --- Initialize plot ---
figure('Color','w');
subplot(2,1,1);
h1=animatedline('Color','r','LineWidth',1.5);
h2=animatedline('Color','b','LineWidth',1.5);
h3=animatedline('Color',[.7 .7 .7],'LineWidth',1,'LineStyle','--');
xlabel('Time (s)'); ylabel('Speed (rad/s)');
title('MRAS Adaptive PID Tracking');
legend({'Plant','Model','Ref'},'Location','best'); grid on;
subplot(2,1,2);
hKp=animatedline('Color','r'); hKi=animatedline('Color','b'); hKd=animatedline('Color','g');
xlabel('Time (s)'); ylabel('Gain'); grid on;
%% --- loop ---
disp('Starting control... Press Ctrl+C to stop');
t0 = tic;
while ishandle(h1)
t = toc(t0);
% --- Read speed from Arduino ---
if s.NumBytesAvailable > 0
line = readline(s);
yp_new = str2double(line);
if ~isnan(yp_new)
yp = speed_alpha*yp + (1-speed_alpha)*yp_new;
end
end
% --- Reference model ---
ym = ym + T*(-am*ym + bm*setpoint);
% --- error ---
e = setpoint - yp;
em = ym - yp;
% --- Basic PID ---
d_raw = (e - e_prev)/T;
d_filt = deriv_alpha*d_filt + (1-deriv_alpha)*d_raw;
I = I + e*T;
uP = Kp*e + Kd*d_filt;
u_tent = uP + Ki*I;
% Saturation and anti-windup
if (u_tent>=PWM_MAX && e>0) || (u_tent<=0 && e<0)
I = I*0.999;
end
u = uP + Ki*I;
pwmOut = min(max(u,0),PWM_MAX);
if pwmOut>0 && pwmOut<PWM_DEAD
pwmOut = PWM_DEAD;
end
% --- Send PWM to Arduino ---
writeline(s, string(round(pwmOut)));
% --- MRAS adaptation ---
freeze = ((pwmOut>=PWM_MAX && em>0) || (pwmOut<=0 && em<0));
if ~freeze
phi_p=e; phi_i=I; phi_d=d_filt;
Kp = Kp + gamma_p*em*phi_p/(1+norm_p*phi_p^2);
Ki = Ki + gamma_i*em*phi_i/(1+norm_i*phi_i^2);
Kd = Kd + gamma_d*em*phi_d/(1+norm_d*phi_d^2);
Kp = min(max(Kp,Kp_min),Kp_max);
Ki = min(max(Ki,Ki_min),Ki_max);
Kd = min(max(Kd,Kd_min),Kd_max);
end
% --- Real-time plotting ---
addpoints(h1,t,yp);
addpoints(h2,t,ym);
addpoints(h3,t,setpoint);
addpoints(hKp,t,Kp); addpoints(hKi,t,Ki); addpoints(hKd,t,Kd);
drawnow limitrate;
e_prev = e;
pause(T);
end
disp('⏹ STOP.'); clear s;
Mathieu NOE
Mathieu NOE on 20 Oct 2025 at 10:11
hello
my first comments :
  • have you identified your plant ? measured the step response (by creating a 0 to whatever PWM value step input)
  • befor implementing advanced non linear PID maybe try with a simpler fixed paramaters PID and then improve by changing the law only one by one parameter.
  • Once you have identified the plant model you can use the well known techniques for PID tuning (start with Ziegler Nichols basic tuning)

Sign in to comment.

More Answers (0)

Products


Release

R2023b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!