forked from XRobots/WiperMotorServo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
IBT_2_Servocontroller.ino
146 lines (119 loc) · 4.59 KB
/
IBT_2_Servocontroller.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Adapted version for IBT_2 H-bridge, fine tuned for a 250w wheelchair motor (75rpm) and a P3022-V1-CW360 rotary hall encoder.
// If you like to use a normal poti, just increase again "potMax" to 1024 for the full resolution.
#include <PID_v1.h> // PID loop from http://playground.arduino.cc/Code/PIDLibrary
// Pin assignments
const int potPin = A0;
const int pwmInputPin = 2;
const int motorPin1 = 9;
const int motorPin2 = 10;
double deadband = 5; // Increased deadband value to reduce micro-oscillations
// PID parameters (retuned for smoother control)
double Pk1 = 5; // Reduced proportional gain for smoother correction
double Ik1 = 0.05; // Slightly increased integral gain for gradual corrections
double Dk1 = 0.5; // Reduced derivative gain to reduce aggressive damping
// PID variables
double Setpoint1, Input1, Output1, Output1a;
PID PID1(&Input1, &Output1, &Setpoint1, Pk1, Ik1, Dk1, DIRECT); // PID Setup
// PWM and timing variables
volatile unsigned long pwm;
volatile boolean done;
unsigned long start;
unsigned long currentMillis;
long previousMillis = 0;
const long interval = 50; // Increased sample time for smoother corrections
// Potentiometer and PWM range settings (for fine-tuning)
int potMin = 0;
int potMax = 400;
int pwmMin = 1000;
int pwmMax = 2000;
int outputMin = -200;
int outputMax = 200;
// Filter variables
double alphaLowPass = 0.5; // Low-pass filter smoothing factor
double alphaHighPass = 0.5; // High-pass filter smoothing factor
double previousPWM = 1500; // Initial guess for PWM (midpoint)
double filteredPWM = 1500; // For the low-pass filter
double highPassPWM = 0; // For the high-pass filter
// Declare pot variable
int pot;
void setup() {
pinMode(pwmInputPin, INPUT);
pinMode(potPin, INPUT);
pinMode(motorPin1, OUTPUT);
pinMode(motorPin2, OUTPUT);
// Set PWM frequency to 25 kHz for pins 9 and 10 (Timer 1)
TCCR1B = TCCR1B & B11111000 | B00000001; // Set the prescaler to 1 (for 25 kHz PWM)
attachInterrupt(digitalPinToInterrupt(pwmInputPin), timeit, CHANGE);
Serial.begin(115200);
// PID Setup
PID1.SetMode(AUTOMATIC);
PID1.SetOutputLimits(outputMin, outputMax);
PID1.SetSampleTime(interval); // Increased sample time to 50 ms
}
void timeit() {
if (digitalRead(pwmInputPin) == HIGH) {
start = micros();
} else {
pwm = micros() - start;
done = true;
}
}
// Function to apply a low-pass filter
double lowPassFilter(double newPWM, double filteredPWM, double alpha) {
return alpha * newPWM + (1 - alpha) * filteredPWM;
}
// Function to apply a high-pass filter
double highPassFilter(double newPWM, double previousPWM, double alpha) {
return alpha * (highPassPWM + newPWM - previousPWM);
}
void loop() {
currentMillis = millis();
if (currentMillis - previousMillis >= interval) { // Start timed event
previousMillis = currentMillis;
// Read potentiometer value
pot = analogRead(potPin);
// Apply a low-pass filter on the PWM signal to smooth high-frequency noise
filteredPWM = lowPassFilter(pwm, filteredPWM, alphaLowPass);
// Apply a high-pass filter to remove low-frequency components (slow drift)
highPassPWM = highPassFilter(pwm, previousPWM, alphaHighPass);
previousPWM = pwm; // Update previous PWM for high-pass filter
// Print debug information
Serial.print("Potentiometer: ");
Serial.print(pot);
Serial.print(" , Filtered PWM (Low-Pass): ");
Serial.print(filteredPWM);
Serial.print(" , High-Pass Filtered PWM: ");
Serial.print(highPassPWM);
Serial.print(" , Raw PWM: ");
Serial.print(pwm);
Serial.print(" , PID Output: ");
Serial.println(Output1);
// Map filtered PWM to output range
Setpoint1 = map(filteredPWM, pwmMin, pwmMax, outputMin, outputMax);
Input1 = map(pot, potMin, potMax, outputMin, outputMax);
// Compute the PID output
PID1.Compute();
// Explicitly set small output values to zero if they are within the deadband
if (abs(Output1) < deadband) {
Output1 = 0; // Treat small output as zero
}
// Deadband implementation to avoid micro-oscillations
if (Output1 == 0) {
// Stop the motor when the PID output is effectively zero
analogWrite(motorPin1, 0);
analogWrite(motorPin2, 0);
} else if (Output1 > 0) {
// Move forward if the output is positive
analogWrite(motorPin1, Output1);
analogWrite(motorPin2, 0);
} else if (Output1 < 0) {
// Move in reverse if the output is negative
Output1a = abs(Output1);
analogWrite(motorPin1, 0);
analogWrite(motorPin2, Output1a);
}
if (!done)
return;
done = false;
} // End of timed event
}