-
Notifications
You must be signed in to change notification settings - Fork 0
/
turns.ts
239 lines (221 loc) · 19.2 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
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; // Переменная для хранения коэффицента фильтра дифференциального регулятора при повороте относительно колеса
/**
* Установить значение максимального времени умного поворота относительно центра колёс в мсек.
* @param timeOut максимальное время в мс, eg: 1000
*/
//% blockId="SetSmartSpinTurnTimeOut"
//% block="максимальное время поворота относительно центра $timeOut мс"
//% inlineInputMode="inline"
//% weight="99" blockGap="8"
//% group="Свойства умных поворотов"
export function SetSmartSpinTurnTimeOut(timeOut: number) {
smartSpinTurnTimeOut = timeOut;
}
/**
* Установить значение максимального времени умного поворота относительно колёса в мсек.
* @param timeOut максимальное время в мс, eg: 1000
*/
//% blockId="SetSmartPivotTurnTimeOut"
//% block="максимальное время поворота относительно колеса $timeOut мс"
//% inlineInputMode="inline"
//% weight="98" blockGap="8"
//% group="Свойства умных поворотов"
export function SetSmartPivotTurnTimeOut(timeOut: number) {
smartPivotTurnTimeOut = timeOut;
}
/**
* Установить значение времени дорегулирования при умном повороте в мс.
* @param timeOut максимальное время в мс, eg: 200
*/
//% blockId="SetSmartTurnDeregTimeOut"
//% block="максимальное время дорегулирования умного поворота $timeOut мс"
//% inlineInputMode="inline"
//% weight="97"
//% group="Свойства умных поворотов"
export function SetSmartTurnDeregTimeOut(timeOut: number) {
smartTurnDeregTimeOut = timeOut;
}
/**
* Установить значение условия ошибки при умном повороте.
* @param maxErr максимальная ошибка, eg: 10
*/
//% blockId="SetSmartTurnConditionErrDifference"
//% block="максимальная ошибка при умном повороте $maxErr определения окончания"
//% inlineInputMode="inline"
//% weight="96" blockGap="8"
//% group="Свойства умных поворотов"
export function SetSmartTurnConditionErrDifference(maxErr: number) {
smartTurnConditionErrDifference = maxErr;
}
/**
* Установить значение условия управляющего воздействия регулятора при умном повороте.
* @param maxU максимальное управляющее воздействие, eg: 10
*/
//% blockId="SetSmartTurnConditionRegDifference"
//% block="максимальное значение управляющего воздействия при умном повороте $maxU определения окончания"
//% inlineInputMode="inline"
//% weight="96" blockGap="8"
//% 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"
//% 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;
}
let lMotEncPrev = leftMotor.angle(); // Считываем значение с энкодера левого мотора перед стартом алгаритма
let rMotEncPrev = rightMotor.angle(); //Считываем значение с энкодера правого мотора перед стартом алгаритма
let calcMotRot = Math.round(deg * getBaseLength() / getWheelRadius()); // Расчёт угла поворота моторов для поворота
automation.pid2.setGains(smartSpinTurnKp, smartSpinTurnKi, smartSpinTurnKd); // Установка коэффициентов ПИД регулятора
automation.pid2.setDerivativeFilter(smartSpinTurnN); // Установить фильтр дифференциального регулятора
automation.pid2.setControlSaturation(-100, 100); // Устанавливаем интервал ПИД регулятора
automation.pid2.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; // Дорегулируемся
let lMotEnc = leftMotor.angle() - lMotEncPrev; // Значение энкодера с левого мотора в текущий момент
let rMotEnc = rightMotor.angle() - rMotEncPrev; // Значение энкодера с правого мотора в текущий момент
let errorL = calcMotRot - lMotEnc; // Ошибки регулирования левой стороны
let errorR = calcMotRot * -1 - rMotEnc; // Ошибки регулирования правой стороны
let error = errorL - errorR; // Расчитываем общую ошибку
automation.pid2.setPoint(error); // Передаём ошибку регулятору
let u = automation.pid2.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); // Сигнал начале дорегулирования
}
leftMotor.run(u); rightMotor.run(-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); // Издаём сигнал завершения дорегулирования
leftMotor.setBrake(true); rightMotor.setBrake(true); // Установка тормоз с удержанием на моторы
leftMotor.stop(); rightMotor.stop(); // Остановка моторов
}
/**
* 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"
//% 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;
}
leftMotor.setBrake(true); rightMotor.setBrake(true); // Установить жёсткий тормоз для моторов
let motEncPrev = 0; // Инициализируем переменную хранения значения с энкодера мотора
if (wheelPivot == WheelPivot.LeftWheel) { // Записываем текущее значение с энкодера нужного мотора и ставим тормоз нужному мотору
leftMotor.stop(); // Тормоз на мотор
motEncPrev = rightMotor.angle(); // Если вращаться нужно вокруг левого, тогда записываем с правого
} else if (wheelPivot == WheelPivot.RightWheel) {
rightMotor.stop(); // Тормоз на мотор
motEncPrev = leftMotor.angle(); // Если вращаться нужно вокруг правого, тогда записываем с левого
}
let calcMotRot = Math.round(((deg * getBaseLength()) / getWheelRadius()) * 2); // Рассчитываем сколько градусов вращать мотор
automation.pid2.setGains(smartPivotTurnKp, smartPivotTurnKi, smartPivotTurnKd); // Устанавливаем коэффиценты ПИД регулятора
automation.pid2.setDerivativeFilter(smartPivotTurnN); // Установить фильтр дифференциального регулятора
automation.pid2.setControlSaturation(-100, 100); // Устанавливаем интервал ПИД регулятора
automation.pid2.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; // Дорегулируемся
automation.pid2.setPoint(error); // Передаём ошибку регулятору
let U = automation.pid2.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); // Издаём сигнал завершения дорегулирования
leftMotor.stop(); rightMotor.stop(); // Остановить моторы
}
}