In my previous post on using Laplace and Z-Transform for building PID controller with Arduino. In that post I provided the schematic but did not explain. So I am writing this note on the hardware interfacing aspect.
🧰 Part 1: Hardware Interfacing in Proteus
The MOTOR-ENCODER component in Proteus is used here, which simulates a DC motor with an optical encoder. Here's how to wire it to an Arduino:
✅ MOTOR-ENCODER Pin Description
Pin | Connect To | Description |
---|---|---|
+ | +12V Supply | Motor power supply |
− | MOSFET Drain | Connect to low side of MOSFET |
Q1 | Arduino pin 9 | Encoder Channel A (quadrature) |
Q2 | Arduino pin 10 | Encoder Channel B (quadrature) |
IDX | Arduino pin 11 | Index pulse (optional) |
(GND/VCC) | Automatically powered | Encoder logic power (internally) |
Control motor speed with an IRF540N N-channel MOSFET:
MOSFET Pin | Connect To |
---|---|
Gate | Arduino pin 5 via 220Ω |
Drain | − terminal of motor |
Source | GND |
Gate→GND | 10kΩ pull-down resistor |
✅ Power Supply
-
Motor side: +12V →
+
terminal of motor. -
Arduino: USB or +5V regulated.
-
Important: Connect all GNDs together (Arduino GND, MOSFET Source, motor GND).
🔌 Interconnection Diagram
🧾 Part 2: Arduino Code Explanation
Reading encoder Q1 and Q2 as quadrature inputs to determine rotation direction and position.
-
Running a PID controller every 100 ms to regulate speed based on encoder feedback.
-
Outputting PWM to pin 5, which controls the IRF540N MOSFET (and thus the motor power).
// PID constants
float Kp = 1.2, Ki = 0.5, Kd = 0.05;
float T = 0.1; // Sampling time = 100 ms
float e[3] = {0}; // PID error buffer
float u = 0; // PWM output
int setSpeed = 10; // target speed in counts per 100 ms
const int pwmPin = 5; // MOSFET gate for motor control
const int Q1Pin = 9; // Encoder Q1
const int Q2Pin = 10; // Encoder Q2
const int IDXPin = 11; // Encoder Index pulse (optional)
volatile long encoderCount = 0;
long lastEncoderCount = 0;
unsigned long lastTime = 0;
// Track last Q1/Q2 to detect direction
int lastQ1 = 0;
int lastQ2 = 0;
void setup() {
pinMode(pwmPin, OUTPUT);
pinMode(Q1Pin, INPUT);
pinMode(Q2Pin, INPUT);
pinMode(IDXPin, INPUT); // Optional
Serial.begin(9600);
Serial.println("Proteus DC Motor Encoder PID Control");
}
void loop() {
// Quadrature decoding (called frequently to detect movement)
updateEncoder();
// PID loop every 100 ms
if (millis() - lastTime >= T * 1000) {
lastTime = millis();
e[2] = e[1];
e[1] = e[0];
// Speed = encoder ticks since last sample
long currentCount = encoderCount;
int feedback = currentCount - lastEncoderCount;
lastEncoderCount = currentCount;
e[0] = setSpeed - feedback;
float du = Kp * (e[0] - e[1]) + Ki * T * e[0] + Kd / T * (e[0] - 2 * e[1] + e[2]);
u += du;
u = constrain(u, 0, 255);
analogWrite(pwmPin, (int)u);
// Display information
Serial.print("Position: ");
Serial.print(encoderCount);
Serial.print(" | Speed: ");
Serial.print(feedback);
Serial.print(" | PWM: ");
Serial.print((int)u);
// Optional: display Q1, Q2, IDX state
Serial.print(" | Q1Q2IDX: ");
Serial.print(digitalRead(Q1Pin));
Serial.print(digitalRead(Q2Pin));
Serial.println(digitalRead(IDXPin));
}
}
// Quadrature decoder
void updateEncoder() {
int q1 = digitalRead(Q1Pin);
int q2 = digitalRead(Q2Pin);
// Detect rising edge on Q1 and determine direction from Q2
if (q1 != lastQ1) {
if (q1 == 1) {
if (q2 == 0) encoderCount++; // CW
else encoderCount--; // CCW
}
}
// Save last states
lastQ1 = q1;
lastQ2 = q2;
}
✅ What You Can Observe in Proteus
Signal | Where to Watch |
---|---|
Encoder pulses | Oscilloscope or logic probe on Q1/Q2 |
PWM duty | Pin 5 (MOSFET gate) |
Motor behavior | Motor symbol animation |
Encoder count | Arduino serial monitor |
🔚 Summary
-
Use Q1 and Q2 for quadrature decoding — no interrupts needed for moderate speed simulation.
-
Use PID to regulate motor speed by adjusting PWM output.
-
Connect Q1/Q2 to Arduino pins 9 and 10 as inputs.
-
Use pin 5 as PWM output to gate of IRF540N MOSFET.
-
Ensure all grounds are common in simulation.