-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathArduino.ino
More file actions
272 lines (230 loc) · 8.87 KB
/
Arduino.ino
File metadata and controls
272 lines (230 loc) · 8.87 KB
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
#include <Arduino.h>
#include <Servo.h>
#include <AccelStepper.h>
const int PIN_ANALOG = A2; // Pin analógico a leer (A2)
/* ===================== Pines ===================== */
// Hall
const uint8_t PIN_HALL_R = A0; // Hall derecho
const uint8_t PIN_HALL_L = A1; // Hall izquierdo
// Servos
const uint8_t PIN_SERVO_FRONT = 32; // Servo dirección delantero
const uint8_t PIN_SERVO_REAR = 33; // Servo dirección trasero
// Stepper 1 (eje trasero)
const uint8_t M1_IN1 = 41;
const uint8_t M1_IN2 = 39;
const uint8_t M1_IN3 = 37;
const uint8_t M1_IN4 = 35;
// Stepper 2 (eje trasero)
const uint8_t M2_IN1 = 43;
const uint8_t M2_IN2 = 45;
const uint8_t M2_IN3 = 47;
const uint8_t M2_IN4 = 49;
/* ==================== Servos ===================== */
Servo servoFront, servoRear;
int SERVO_FRONT_CENTER_US = 1000; // 1000
int SERVO_REAR_CENTER_US = 2000; //2000
const int MAX_DELTA_US = 500;
/* =============== Sentido y ganancias ============= */
const int E_SIGN = +1;
float Kp_us = 2000.0f;
float Kd_us = 350.0f;
float deadband = 0.02f;
float alpha = 0.2f;
/* ============== Rangos fijos Hall ================ */
float L_min = 2040;
float L_max = 2060;
float R_min = 2080;
float R_max = 2115;
/* ================ Trim del servo ================= */
float SERVO_FRONT_TRIM_US = 0.0f;
const float NO_FIELD_COUNTS = 20.0f;
const float TRIM_KI_US_PER_S = 400.0f;
const float TRIM_MAX_ABS_US = 200.0f;
/* ======== Servo trasero relación/sentido ========= */
const bool REAR_INVERT = true;
const float REAR_RATIO = 1.0f;
/* ============== Slew-rate (suavizado) ============ */
float SLEW_US_PER_SEC_FRONT = 2000.0f;
float SLEW_US_PER_SEC_REAR = 2000.0f;
int servo_front_us_prev = SERVO_FRONT_CENTER_US;
int servo_rear_us_prev = SERVO_REAR_CENTER_US;
/* ================== Steppers ===================== */
AccelStepper stepper1(AccelStepper::HALF4WIRE, M1_IN1, M1_IN3, M1_IN2, M1_IN4);
AccelStepper stepper2(AccelStepper::HALF4WIRE, M2_IN1, M2_IN3, M2_IN2, M2_IN4);
const long STEPS_PER_REV = 4096;
float wheel_rps = 2.30f;
float steps_per_second = wheel_rps * STEPS_PER_REV;
float MAX_SPS = 1500.0f;
bool invert_stepper1 = true;
bool invert_stepper2 = true;
/* ================== Estado ======================= */
float e_filt = 0.0f, e_prev = 0.0f;
unsigned long t_prev = 0;
const unsigned long CTRL_MS = 2;
const unsigned long PRINT_MS = 50;
unsigned long t_last_ctrl = 0;
unsigned long t_last_print = 0;
// ======= ADDED: Hall ignore/read state (must be global) =======
bool hallL_enabled = true; // true = read left sensor, false = ignore left
bool hallR_enabled = true; // true = read right sensor, false = ignore right
bool go_straight = false; // true = force straight (center servos)
// =============================================================
/* ================= Utilidades ==================== */
int clampMicroseconds(int u) {
if (u < -MAX_DELTA_US) return -MAX_DELTA_US;
if (u > MAX_DELTA_US) return MAX_DELTA_US;
return u;
}
int readStableAnalog(uint8_t pin) {
long acc = 0; const int N = 6;
for (int i = 0; i < N; ++i) acc += analogRead(pin);
return (int)(acc / N);
}
float ema(float x, float y_prev, float a) { return a * x + (1.0f - a) * y_prev; }
/* ================= Steppers ====================== */
void setBothStepperSpeeds(float sps) {
if (sps > MAX_SPS) sps = MAX_SPS;
if (sps < -MAX_SPS) sps = -MAX_SPS;
steps_per_second = sps;
float s1 = invert_stepper1 ? -sps : sps;
float s2 = invert_stepper2 ? -sps : sps;
stepper1.setSpeed(s1);
stepper2.setSpeed(s2);
}
// ======= zmineno!!! =======
// ======= !!! sensor ignorieren =======
void handleESP32Command() {
if (Serial1.available()) {
String cmd = Serial1.readStringUntil('\n');
cmd.trim();
if (cmd == "sensor left on") {
// читати тільки ЛІВИЙ
hallL_enabled = true;
hallR_enabled = false;
go_straight = false;
}
else if (cmd == "sensor right on") {
// читати тільки ПРАВИЙ
hallL_enabled = false;
hallR_enabled = true;
go_straight = false;
}
else if (cmd == "sensor both off") {
// ігнорувати обидва датчики
hallL_enabled = false;
hallR_enabled = false;
// їхати прямо
go_straight = true;
}
else if (cmd == "sensor both on") {
// читати обидва датчики
hallL_enabled = true;
hallR_enabled = true;
// включаємо нормальний режим PD
go_straight = false;
}
}
}
// ======= zmineno!!! =======
/* =================== Setup ======================= */
void setup() {
analogReadResolution(12);
pinMode(PIN_ANALOG, INPUT);
Serial.begin(115200);
Serial1.begin(115200);
unsigned long t_start = millis();
while (!Serial && (millis() - t_start < 2000)) {}
pinMode(PIN_HALL_R, INPUT);
pinMode(PIN_HALL_L, INPUT);
servoFront.attach(PIN_SERVO_FRONT);
servoRear.attach(PIN_SERVO_REAR);
servoFront.writeMicroseconds(SERVO_FRONT_CENTER_US);
servoRear.writeMicroseconds(SERVO_REAR_CENTER_US);
delay(200);
stepper1.setMaxSpeed(MAX_SPS);
stepper2.setMaxSpeed(MAX_SPS);
setBothStepperSpeeds(wheel_rps * STEPS_PER_REV);
t_prev = millis();
t_last_ctrl = t_prev;
t_last_print = t_prev;
Serial.println(F("# v2.3 (valores fijos Lmin/Lmax/Rmin/Rmax)"));
Serial.print(F("L_min=")); Serial.println(L_min);
Serial.print(F("L_max=")); Serial.println(L_max);
Serial.print(F("R_min=")); Serial.println(R_min);
Serial.print(F("R_max=")); Serial.println(R_max);
}
/* ==================== Loop ======================= */
void loop() {
handleESP32Command();
int value = analogRead(PIN_ANALOG);
float voltage = value * (3.3 / 4095);
if (voltage >= 2.0) {
stepper1.runSpeed();
stepper2.runSpeed();
}
unsigned long now = millis();
if (now - t_last_ctrl >= CTRL_MS) {
float dt = (now - t_last_ctrl) / 1000.0f;
if (dt < 0.0005f) dt = 0.0005f;
t_last_ctrl = now;
if (go_straight) {
servoFront.writeMicroseconds(SERVO_FRONT_CENTER_US + (int)SERVO_FRONT_TRIM_US);
servoRear.writeMicroseconds(SERVO_REAR_CENTER_US);
servo_front_us_prev = SERVO_FRONT_CENTER_US + (int)SERVO_FRONT_TRIM_US;
servo_rear_us_prev = SERVO_REAR_CENTER_US;
e_filt = 0.0f;
e_prev = 0.0f;
return; // вихід з loop(), щоб PD не рахувався
}
int R_raw = hallR_enabled ? readStableAnalog(PIN_HALL_R) : (int)R_min;
int L_raw = hallL_enabled ? readStableAnalog(PIN_HALL_L) : (int)L_min;
float rel_R = R_min - R_raw;
float rel_L = L_min - L_raw;
float e = 0.0f;
bool inNeutral_R = (R_raw >= R_min && R_raw <= R_max);
bool inNeutral_L = (L_raw >= L_min && L_raw <= L_max);
if (!(inNeutral_R && inNeutral_L)) {
const float eps = 1.0f;
float denom = fabsf(R_min - R_raw) + fabsf(L_min - L_raw) + eps;
e = ((R_min - R_raw) - (L_min - L_raw)) / denom;
e *= (float)E_SIGN;
} else {
e = 0.0f;
}
e_filt = ema(e, e_filt, alpha);
float e_db = (fabs(e_filt) < deadband) ? 0.0f : e_filt;
float de = (e_filt - e_prev) / dt;
int u_us = (int)(Kp_us * e_db + Kd_us * de);
int u_us_clamped = clampMicroseconds(u_us);
int front_center_eff = SERVO_FRONT_CENTER_US + (int)SERVO_FRONT_TRIM_US;
int rear_center_eff = SERVO_REAR_CENTER_US;
int desired_front_us = front_center_eff + u_us_clamped;
int rear_delta = (int)(REAR_RATIO * u_us_clamped);
if (REAR_INVERT) rear_delta = -rear_delta;
int desired_rear_us = rear_center_eff + rear_delta;
float max_step_f = SLEW_US_PER_SEC_FRONT * dt;
float delta_f = (float)desired_front_us - (float)servo_front_us_prev;
delta_f = constrain(delta_f, -max_step_f, max_step_f);
int servo_front_us = servo_front_us_prev + (int)delta_f;
float max_step_r = SLEW_US_PER_SEC_REAR * dt;
float delta_r = (float)desired_rear_us - (float)servo_rear_us_prev;
delta_r = constrain(delta_r, -max_step_r, max_step_r);
int servo_rear_us = servo_rear_us_prev + (int)delta_r;
servoFront.writeMicroseconds(servo_front_us);
servoRear.writeMicroseconds(servo_rear_us);
servo_front_us_prev = servo_front_us;
servo_rear_us_prev = servo_rear_us;
e_prev = e_filt;
}
if (Serial && (millis() - t_last_print >= PRINT_MS)) {
t_last_print = millis();
Serial.print(F("L_raw:")); Serial.print(analogRead(PIN_HALL_L)); Serial.print('\t');
Serial.print(F("R_raw:")); Serial.print(analogRead(PIN_HALL_R)); Serial.print('\t');
Serial.print(F("Lmin:")); Serial.print(L_min); Serial.print('\t');
Serial.print(F("Lmax:")); Serial.print(L_max); Serial.print('\t');
Serial.print(F("Rmin:")); Serial.print(R_min); Serial.print('\t');
Serial.print(F("Rmax:")); Serial.print(R_max); Serial.print('\t');
Serial.print(F("servo_front:")); Serial.print(servo_front_us_prev); Serial.print('\t');
Serial.print(F("servo_rear:")); Serial.print(servo_rear_us_prev); Serial.print('\n');
}
}