-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathturns.ts
394 lines (375 loc) · 29.1 KB
/
turns.ts
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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
namespace chassis {
/**
* Synchronized rotation of the chassis relative to the center at the desired angle at a certain speed.
* For example, if deg > 0, then the robot will rotate to the right, and if deg < 0, then to the left.
* The speed must be positive!
* Синхронизированный поворот шасси относительно центра на нужный угол с определенной скоростью.
* Например, если градусов > 0, то робот будет поворачиваться вправо, а если градусов < 0, то влево.
* Скорость должна быть положительной!
* @param deg угол вращения в градусах, eg: 90
* @param speed скорость ващения, eg: 50
*/
//% blockId="ChassisSpinTurn"
//% block="sync chassis spin turn $deg\\° at $speed\\% relative to center wheel axis"
//% block.loc.ru="синхронизированный поворот шасси на $deg\\° с $speed\\% относительно центра оси колёс"
//% inlineInputMode="inline"
//% speed.shadow="motorSpeedPicker"
//% weight="99" blockGap="8"
//% subcategory="Повороты"
//% group="Синхронизированные повороты"
export function SpinTurn(deg: number, speed: number) {
//if (!motorsPair) return;
if (deg == 0 || speed == 0) {
stop(true);
return;
} else if (speed < 0) {
music.playSoundEffectUntilDone(sounds.systemGeneralAlert);
control.panic(1);
}
speed = Math.clamp(0, 100, speed >> 0); // We limit the speed of the motor from -100 to 100 and cut off the fractional part
const emlPrev = leftMotor.angle(), emrPrev = rightMotor.angle(); // We read the value from the encoder from the left motor, right motor before starting
const calcMotRot = Math.round(deg * getBaseLength() / getWheelDiametr()); // Расчёт угла поворота моторов для поворота
if (deg > 0) advmotctrls.syncMotorsConfig(speed, -speed);
else if (deg < 0) advmotctrls.syncMotorsConfig(-speed, speed);
pidChassisSync.setGains(chassis.getSyncRegulatorKp(), chassis.getSyncRegulatorKi(), chassis.getSyncRegulatorKd()); // Установка коэффицентов ПИД регулятора
pidChassisSync.setControlSaturation(-100, 100); // Установка интервалов регулирования
pidChassisSync.reset(); // Сбросить регулятор
let prevTime = 0;
while (true) {
let currTime = control.millis();
let dt = currTime - prevTime;
prevTime = currTime;
let eml = leftMotor.angle() - emlPrev;
let emr = rightMotor.angle() - emrPrev;
if ((Math.abs(eml) + Math.abs(emr)) / 2 >= Math.abs(calcMotRot)) break;
let error = advmotctrls.getErrorSyncMotors(eml, emr);
pidChassisSync.setPoint(error);
let U = pidChassisSync.compute(dt, 0);
let powers = advmotctrls.getPwrSyncMotors(U);
setSpeedsCommand(powers.pwrLeft, powers.pwrRight); // Set power/speed motors
control.pauseUntilTime(currTime, 1);
}
stop(true); // Break at hold
}
/**
* Synchronized rotation to the desired angle relative to one of the wheels.
* A positive speed is set for forward rotation, and a negative speed is set for backward rotation.
* The value of the rotation angle is always positive!
* Синхронизированный поворот на нужный угол относительно одного из колес.
* Для вращения вперёд устанавливается положительная скорость, а назад - отрицательная.
* Значение угла поворота всегда положительное!
* @param deg угол вращения в градусах, eg: 90
* @param speed скорость вращения, eg: 50
*/
//% blockId="ChassisPivotTurn"
//% block="sync chassis pivot turn $deg\\° at $speed\\% pivot $wheelPivot"
//% block.loc.ru="синхронизированный поворот шасси на $deg\\° с $speed\\% относительно $wheelPivot"
//% inlineInputMode="inline"
//% speed.shadow="motorSpeedPicker"
//% weight="98"
//% subcategory="Повороты"
//% group="Синхронизированные повороты"
export function PivotTurn(deg: number, speed: number, wheelPivot: WheelPivot) {
//if (!motorsPair) return;
if (deg == 0 || speed == 0) {
stop(true);
return;
} else if (deg < 0) {
music.playSoundEffectUntilDone(sounds.systemGeneralAlert);
control.panic(2);
}
speed = Math.clamp(0, 100, speed >> 0); // We limit the speed of the motor from -100 to 100 and cut off the fractional part
const emlPrev = leftMotor.angle(), emrPrev = rightMotor.angle(); // Считываем с левого мотора и правого мотора значения энкодера перед стартом алгаритма
const calcMotRot = Math.round(((Math.abs(deg) * getBaseLength()) / getWheelDiametr()) * 2); // Расчёт угла поворота моторов для поворота
stop(true, 0); // Установить тормоз и удержание моторов перед поворотом
if (wheelPivot == WheelPivot.LeftWheel) advmotctrls.syncMotorsConfig(0, speed);
else if (wheelPivot == WheelPivot.RightWheel) advmotctrls.syncMotorsConfig(speed, 0);
else return;
pidChassisSync.setGains(chassis.getSyncRegulatorKp(), chassis.getSyncRegulatorKi(), chassis.getSyncRegulatorKd()); // Установка коэффицентов ПИД регулятора
pidChassisSync.setControlSaturation(-100, 100); // Установка интервалов регулирования
pidChassisSync.reset(); // Сбросить регулятор
let prevTime = 0;
while (true) {
let currTime = control.millis();
let dt = currTime - prevTime;
prevTime = currTime;
let eml = leftMotor.angle() - emlPrev;
let emr = rightMotor.angle() - emrPrev;
if (wheelPivot == WheelPivot.LeftWheel && Math.abs(emr) >= calcMotRot) break;
else if (wheelPivot == WheelPivot.RightWheel && Math.abs(eml) >= calcMotRot) break;
let error = advmotctrls.getErrorSyncMotors(eml, emr);
pidChassisSync.setPoint(error);
let U = pidChassisSync.compute(dt, 0);
let powers = advmotctrls.getPwrSyncMotors(U);
if (wheelPivot == WheelPivot.LeftWheel) rightMotor.run(powers.pwrRight);
else if (wheelPivot == WheelPivot.RightWheel) leftMotor.run(powers.pwrLeft);
control.pauseUntilTime(currTime, 1);
}
stop(true); // Break at hold
}
/**
* Synchronized rotation of the chassis relative to the center at the desired angle at a certain speed.
* For example, if deg > 0, then the robot will rotate to the right, and if deg < 0, then to the left.
* The speed must be positive!
* Синхронизированный поворот шасси относительно центра на нужный угол с определенной скоростью.
* Например, если градусов > 0, то робот будет поворачиваться вправо, а если градусов < 0, то влево.
* Скорость должна быть положительной!
* @param deg rotation value in degrees, eg: 90
* @param speed turning speed value, eg: 30
*/
//% blockId="ChassisRampSpinTurn"
//% block="sync chassis spin turn $deg\\° at $speed\\% relative to center wheel axis"
//% block.loc.ru="синхронизированный поворот шасси на $deg\\° с $speed\\% относительно центра оси колёс"
//% inlineInputMode="inline"
//% speed.shadow="motorSpeedPicker"
//% weight="89" blockGap="8"
//% subcategory="Повороты"
//% group="Синхронизированные повороты с ускорениями"
function RampSpinTurn(deg: number, minSpeed: number, maxSpeed: number) {
return;
}
/**
* Synchronized rotation to the desired angle relative to one of the wheels.
* A positive speed is set for forward rotation, and a negative speed is set for backward rotation.
* The value of the rotation angle is always positive!
* Синхронизированный поворот на нужный угол относительно одного из колес.
* Для вращения вперёд устанавливается положительная скорость, а назад - отрицательная.
* Значение угла поворота всегда положительное!
* @param deg rotation value in degrees, eg: 90
* @param speed turning speed value, eg: 30
*/
//% blockId="ChassisRampPivotTurn"
//% block="sync chassis pivot turn $deg\\° at $minSpeed\\% $maxSpeed\\% pivot $wheelPivot"
//% block.loc.ru="синхронизированный поворот шасси на $deg\\° с $minSpeed\\% $maxSpeed\\% относительно $wheelPivot"
//% inlineInputMode="inline"
//% speed.shadow="motorSpeedPicker"
//% weight="88"
//% subcategory="Повороты"
//% group="Синхронизированные повороты с ускорениями"
function RampPivotTurn(deg: number, minSpeed: number, maxSpeed: number, wheelPivot: WheelPivot) {
return;
}
}
namespace chassis {
export let smartSpinTurnTimeOut = 800; // Максимальное время умного поворота относительно центра в мм
export let smartPivotTurnTimeOut = 1000; // Максимальное время умного поворота относительно колеса в мм
export let smartTurnDeregTimeOut = 200; // Время дорегулирования в умном повороте
export let smartTurnConditionErrDifference = 10; // Пороговое значения ошибки для регулятора умного поворота, что поворот выполнен
export let smartTurnConditionRegDifference = 10; // Пороговое значение регулятора (мощности регулятора) умного поворота для определения выполненного поворота
export let smartSpinTurnSpeed = 50; // Переменная для хранения скорости при повороте относительно центра оси
export let smartSpinTurnKp = 0.25; // Переменная для хранения коэффицента пропорционального регулятора при повороте относительно центра оси
export let smartSpinTurnKi = 0; // Переменная для хранения коэффицента интегорального регулятора при повороте относительно центра оси
export let smartSpinTurnKd = 2; // Переменная для хранения коэффицента дифференциального регулятора при повороте относительно центра оси
export let smartSpinTurnN = 0; // Переменная для хранения коэффицента фильтра дифференциального регулятора при повороте относительно центра оси
export let smartPivotTurnSpeed = 60; // Переменная для хранения скорости при повороте относительно колеса
export let smartPivotTurnKp = 0.5; // Переменная для хранения коэффицента пропорционального регулятора при повороте относительно колеса
export let smartPivotTurnKi = 0; // Переменная для хранения коэффицента интегорального регулятора при повороте относительно колеса
export let smartPivotTurnKd = 2; // Переменная для хранения коэффицента дифференциального регулятора при повороте относительно колеса
export let smartPivotTurnN = 0; // Переменная для хранения коэффицента фильтра дифференциального регулятора при повороте относительно колеса
export const pidSmartTurns = new automation.PIDController(); // PID для умных поворотов
/**
* Установить значение максимального времени умного поворота относительно центра колёс в мсек.
* @param timeOut максимальное время в мс, eg: 1000
*/
//% blockId="SetSmartSpinTurnTimeOut"
//% block="максимальное время поворота относительно центра $timeOut мс"
//% inlineInputMode="inline"
//% weight="99" blockGap="8"
//% subcategory="Повороты 2"
//% group="Свойства умных поворотов"
export function SetSmartSpinTurnTimeOut(timeOut: number) {
smartSpinTurnTimeOut = timeOut;
}
/**
* Установить значение максимального времени умного поворота относительно колёса в мсек.
* @param timeOut максимальное время в мс, eg: 1000
*/
//% blockId="SetSmartPivotTurnTimeOut"
//% block="максимальное время поворота относительно колеса $timeOut мс"
//% inlineInputMode="inline"
//% weight="98" blockGap="8"
//% subcategory="Повороты 2"
//% group="Свойства умных поворотов"
export function SetSmartPivotTurnTimeOut(timeOut: number) {
smartPivotTurnTimeOut = timeOut;
}
/**
* Установить значение времени дорегулирования при умном повороте в мс.
* @param timeOut максимальное время в мс, eg: 200
*/
//% blockId="SetSmartTurnDeregTimeOut"
//% block="максимальное время дорегулирования умного поворота $timeOut мс"
//% inlineInputMode="inline"
//% weight="97"
//% subcategory="Повороты 2"
//% group="Свойства умных поворотов"
export function SetSmartTurnDeregTimeOut(timeOut: number) {
smartTurnDeregTimeOut = timeOut;
}
/**
* Установить значение условия ошибки при умном повороте.
* @param maxErr максимальная ошибка, eg: 10
*/
//% blockId="SetSmartTurnConditionErrDifference"
//% block="максимальная ошибка при умном повороте $maxErr определения окончания"
//% inlineInputMode="inline"
//% weight="96" blockGap="8"
//% subcategory="Повороты 2"
//% group="Свойства умных поворотов"
export function SetSmartTurnConditionErrDifference(maxErr: number) {
smartTurnConditionErrDifference = maxErr;
}
/**
* Установить значение условия управляющего воздействия регулятора при умном повороте.
* @param maxU максимальное управляющее воздействие, eg: 10
*/
//% blockId="SetSmartTurnConditionRegDifference"
//% block="максимальное значение управляющего воздействия при умном повороте $maxU определения окончания"
//% inlineInputMode="inline"
//% weight="96" blockGap="8"
//% subcategory="Повороты 2"
//% group="Свойства умных поворотов"
export function SetSmartTurnConditionRegDifference(maxU: number) {
smartTurnConditionRegDifference = maxU;
}
/**
* Rotation relative to the center of the wheels with a regulator.
* Поворот относительно центра колёс c регулятором.
* @param deg угол в градусах поворота в градусах, где положительное число - вправо, а отрицательное влево, eg: 90
* @param debug отладка на экран, eg: false
*/
//% blockId="SmartSpinTurn"
//% block="smart turn at $deg\\° relative center of wheels||params = $params|debug $debug"
//% block.loc.ru="умный поворот на $deg\\° относительно центра оси колёс||параметры = $params|отдалка $debug"
//% expandableArgumentMode="toggle"
//% inlineInputMode="inline"
//% debug.shadow="toggleOnOff"
//% weight="99" blockGap="8"
//% subcategory="Повороты 2"
//% group="Умные повороты с регулятором"
export function SmartSpinTurn(deg: number, params?: params.LineFollowInterface, debug: boolean = false) {
if (deg == 0) return;
if (params) {
if (params.speed) smartSpinTurnSpeed = params.speed;
if (params.Kp) smartSpinTurnKp = params.Kp;
if (params.Ki) smartSpinTurnKi = params.Ki;
if (params.Kd) smartSpinTurnKd = params.Kd;
if (params.N) smartSpinTurnN = params.N;
}
const lMotEncPrev = leftMotor.angle(), rMotEncPrev = rightMotor.angle(); // Считываем значение с энкодера левого мотора и правого мотора перед стартом алгаритма
const calcMotRot = Math.round(deg * getBaseLength() / getWheelDiametr()); // Расчёт угла поворота моторов для поворота
pidSmartTurns.setGains(smartSpinTurnKp, smartSpinTurnKi, smartSpinTurnKd); // Установка коэффициентов ПИД регулятора
pidSmartTurns.setDerivativeFilter(smartSpinTurnN); // Установить фильтр дифференциального регулятора
pidSmartTurns.setControlSaturation(-100, 100); // Устанавливаем интервал ПИД регулятора
pidSmartTurns.reset(); // Сброс ПИД регулятора
let isTurned = false; // Флажок о повороте
let prevTime = 0; // Переменная предыдущего времения для цикла регулирования
let deregStartTime = 0; // Переменная для хранения времени старта таймера дорегулирования
let startTime = control.millis(); // Стартовое время алгоритма
while (true) { // Цикл регулирования
let currTime = control.millis(); // Текущее время
let dt = currTime - prevTime; // Время выполнения итерации цикла
prevTime = currTime; // Обновляем переменную предыдущего времени на текущее время для следующей итерации
if (isTurned && currTime - deregStartTime >= smartTurnDeregTimeOut || currTime - startTime >= smartSpinTurnTimeOut) break; // Дорегулируемся
const lMotEnc = leftMotor.angle() - lMotEncPrev; // Значение энкодера с левого мотора в текущий момент
const rMotEnc = rightMotor.angle() - rMotEncPrev; // Значение энкодера с правого мотора в текущий момент
const errorL = calcMotRot - lMotEnc; // Ошибки регулирования левой стороны
const errorR = calcMotRot * -1 - rMotEnc; // Ошибки регулирования правой стороны
const error = errorL - errorR; // Расчитываем общую ошибку
pidSmartTurns.setPoint(error); // Передаём ошибку регулятору
let u = pidSmartTurns.compute(dt, 0); // Вычисляем и записываем значение с регулятора
u = Math.constrain(u, -smartSpinTurnSpeed, smartSpinTurnSpeed); // Ограничение скорости
if (!isTurned && Math.abs(error) <= smartTurnConditionErrDifference && Math.abs(u) <= smartTurnConditionRegDifference) { // Если почти повернулись до конца при маленькой ошибке и маленькой мощности регулятора
isTurned = true; // Повернулись до нужного градуса
deregStartTime = control.millis(); // Время старта таймер времени для дорегулирования
music.playToneInBackground(587, 50); // Сигнал начале дорегулирования
}
setSpeedsCommand(u, -u); // Передаём управляющее воздействие как скорости на моторы
if (debug) { // Отладка
brick.clearScreen();
brick.showValue("calcMotRot", calcMotRot, 1);
brick.showValue("lMotEnc", lMotEnc, 2);
brick.showValue("rMotEnc", rMotEnc, 3);
brick.showValue("errorL", errorL, 4);
brick.showValue("errorR", errorR, 5);
brick.showValue("error", error, 6);
brick.showValue("u", u, 7);
brick.showValue("dt", dt, 12);
}
control.pauseUntilTime(currTime, 10); // Ожидание выполнения цикла
}
music.playToneInBackground(622, 100); // Издаём сигнал завершения дорегулирования
chassis.stop(true); // Остановка моторов с удержанием
}
/**
* Turn relative to the left or right wheel with a regulator.
* Поворот относительно левого или правого колеса c регулятором.
* @param deg угол в градусах поворота, где положительное число - вправо, а отрицательное влево, eg: 90
* @param wheelPivot относительно колеса, eg: WheelPivot.LeftWheel
* @param debug отладка на экран, eg: false
*/
//% blockId="SmartPivotTurn"
//% block="smart turn at $deg\\° relative $wheelPivot wheel||params = $params|debug %debug"
//% block.loc.ru="умный поворот на $deg\\° относительно $wheelPivot колеса||параметры = $params|отладка %debug"
//% expandableArgumentMode="toggle"
//% inlineInputMode="inline"
//% debug.shadow="toggleOnOff"
//% weight="98"
//% subcategory="Повороты 2"
//% group="Умные повороты с регулятором"
export function SmartPivotTurn(deg: number, wheelPivot: WheelPivot, params?: params.LineFollowInterface, debug: boolean = false) {
if (deg == 0) return;
if (params) {
if (params.speed) smartPivotTurnSpeed = params.speed;
if (params.Kp) smartPivotTurnKp = params.Kp;
if (params.Ki) smartPivotTurnKi = params.Ki;
if (params.Kd) smartPivotTurnKd = params.Kd;
if (params.N) smartPivotTurnN = params.N;
}
stop(true, 0); // Остановить и установить жёсткий тормоз для моторов
let motEncPrev = 0; // Инициализируем переменную хранения значения с энкодера мотора
// Записываем текущее значение с энкодера нужного мотора и ставим тормоз нужному мотору
if (wheelPivot == WheelPivot.LeftWheel) motEncPrev = rightMotor.angle(); // Если вращаться нужно вокруг левого, тогда записываем с правого
else if (wheelPivot == WheelPivot.RightWheel) motEncPrev = leftMotor.angle(); // Если вращаться нужно вокруг правого, тогда записываем с левого
let calcMotRot = Math.round(((deg * getBaseLength()) / getWheelDiametr()) * 2); // Рассчитываем сколько градусов вращать мотор
pidSmartTurns.setGains(smartPivotTurnKp, smartPivotTurnKi, smartPivotTurnKd); // Устанавливаем коэффиценты ПИД регулятора
pidSmartTurns.setDerivativeFilter(smartPivotTurnN); // Установить фильтр дифференциального регулятора
pidSmartTurns.setControlSaturation(-100, 100); // Устанавливаем интервал ПИД регулятора
pidSmartTurns.reset(); // Сбросить ПИД регулятора
let motEnc = 0; // Переменная для хранения значения с энкодера
let isTurned = false; // Флажок о повороте
let deregStartTime = 0; // Переменная для хранения времени старта таймера дорегулирования
let prevTime = 0; // Переменная предыдущего времения для цикла регулирования
let startTime = control.millis(); // Стартовое время алгоритма
while (true) { // Цикл регулирования
let currTime = control.millis(); // Текущее время
let dt = currTime - prevTime; // Время выполнения итерации цикла
prevTime = currTime; // Обновляем переменную предыдущего времени на текущее время для следующей итерации
if (wheelPivot == WheelPivot.LeftWheel) motEnc = rightMotor.angle() - motEncPrev; // Значение левого энкодера мотора в текущий момент
else if (wheelPivot == WheelPivot.RightWheel) motEnc = leftMotor.angle() - motEncPrev; // Значение правого энкодера мотора в текущий момент
let error = calcMotRot - motEnc; // Ошибка регулирования
if (isTurned && currTime - deregStartTime >= smartTurnDeregTimeOut || currTime - startTime >= smartPivotTurnTimeOut) break; // Дорегулируемся
pidSmartTurns.setPoint(error); // Передаём ошибку регулятору
let U = pidSmartTurns.compute(dt, 0); // Записываем в переменную управляющее воздействие регулятора
U = Math.constrain(U, -smartPivotTurnSpeed, smartPivotTurnSpeed); // Ограничить скорость по входному параметру
if (!isTurned && Math.abs(error) <= smartTurnConditionErrDifference && Math.abs(U) <= smartTurnConditionRegDifference) { // Если почти повернулись до конца
isTurned = true; // Повернулись до нужного градуса
deregStartTime = control.millis(); // Время старта таймер времени для дорегулирования
music.playToneInBackground(587, 50); // Сигнал начале дорегулирования
}
if (wheelPivot == WheelPivot.LeftWheel) rightMotor.run(U); // Передаём правому мотору управляющее воздействие
else if (wheelPivot == WheelPivot.RightWheel) leftMotor.run(U); // Передаём левому мотору управляющее воздействие
if (debug) { // Выводим для отладки на экран
brick.clearScreen();
brick.showValue("calcMotRot", calcMotRot, 1);
brick.showValue("motEnc", motEnc, 2);
brick.showValue("error", error, 3);
brick.showValue("U", U, 4);
brick.showValue("dt", dt, 12);
}
control.pauseUntilTime(currTime, 10); // Ожидание выполнения цикла
}
music.playToneInBackground(622, 100); // Издаём сигнал завершения дорегулирования
chassis.stop(true); // Остановить моторы
}
}