Качели Arduino PID: машина для балансировки шариков.........
Взгляд на балансировочные качели PID от norwegiancreation с использованием Arduino.
Видео этой работы:
https://gyazo.com/a7e7b8c4ef73c828a3449bddea8c76b7
https://gyazo.com/194d471b278426e594c36b10ec67122b
https://gyazo.com/78c361639dc5b48876ff313b620b8ae2
Части:
Ардуино УНО
Mopei MG 996R или Hitec HS-422 Servo (большинство аналогичных RC-сервоприводов подходят)
ИК-датчик Sharp GP2Y0A41SK0F (8-30 см) (аналоговый выход)
2 аккумулятора Samsung 30Q 18650 (подойдет все, что может питать сервопривод)
Стандартная батарея 9 В.
потенциометр 10к
Перфорированная электрическая плата
Шарикоподшипник для балансировки или распечатайте собственный мяч на 3D-принтере
Чехол для аккумулятора 2s 18650
9 В → разъем питания
x14 болтов/винтов 3 мм для крепления деталей
х14 гаек 3 мм для крепления деталей
шайбы х14 для крепления деталей
Штекер XT30 (лучше XT 60 или 90, но я использовал XT30)
Розетка XT30 (лучше XT 60 или 90, но я использовал XT30)
6x перемычек
Запасной провод для перфорированной платы
4 шестигранных проставки с резьбой 3 мм
Алюминиевый сервопривод (или распечатайте самостоятельно)
5 резиновых ножек (они не нужны)
Это довольно просто собрать. Это можно сделать с помощью макета, чтобы избежать пайки; с помощью перфорированной платы.
Вот код Ардуино.
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
#include
/*ПОСТОЯННЫЕ ПОЛОЖЕНИЯ СЕРВО*/
#define SERVO_OFFSET 1425 //центральное положение
#define SERVO_MIN 1000
#define SERVO_MAX 1900
/*ССЫЛОЧНЫЙ ДИАПАЗОН*/
#define REFERENCE_MIN 4.5
#define REFERENCE_MAX 7.0
/*ДЕЛЬТА Т*/
#define DT 0.001 //секунды
/*ПАРАМЕТРЫ ПИД*/
#define Kp 0.7 //коэффициент пропорциональности
#define Ki 0.2 //интегральный коэффициент
#define Kd 0.2 //производный коэффициент
/*Увеличение масштаба до Servo.writeMilliсекунд*/
#define OUTPUT_UPSCALE_FACTOR 10
/*ЕМА АЛЬФАС*/
#define SENSOR_EMA_a 0,05
#define SETPOINT_EMA_a 0,01
/*ОБРАБОТКА ШИПОВ ДАТЧИКА*/
#define SENSOR_NOISE_SPIKE_THRESHOLD 15
#define SENSOR_NOISE_LP_THRESHOLD 300
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max);
Сервопривод мойсерво;
/*ПИНЫ ДЛЯ АРДУИНО*/
INT Sensor_pin = 0;
интервал pot_pin = 1;
интервал servo_pin = 3;
/*ИНИЦИАЛИЗАЦИЯ ПЕРЕМЕННЫХ EMA*/
плавающий датчик_filtered = 0,0;
интервал pot_filtered = 0;
/*ГЛОБАЛЬНЫЕ СЕНСОРНЫЕ ПЕРЕМЕННЫЕ ОБРАБОТКИ ШУМА*/
int Last_sensor_value = AnalogRead(sensor_pin);
int old_sensor_value = AnalogRead(sensor_pin);
/*ГЛОБАЛЬНЫЕ ПИД-ПЕРЕМЕННЫЕ*/
плавать предыдущая_ошибка = 0;
плавающий интеграл = 0;
недействительная настройка() {
Serial.begin(115200);
myservo.attach(servo_pin);
}
недействительный цикл() {
/*НАЧАЛО ДЕЛЬТА Т ВРЕМЕНИ*/
unsigned long my_time = millis();
/*ЧИТАЙТЕ POT И ЗАПУСКАЙТЕ EMA POT*/
int pot_value = AnalogRead(pot_pin);
pot_filtered = (SETPOINT_EMA_a*pot_value) + ((1-SETPOINT_EMA_a)*pot_filtered);
/*СОПОСТАВЛЕНИЕ ПОЛОЖЕНИЯ ПОТЕНЦИАЛА В ДИАПАЗОН УСТАВКИ CM*/
уставка с плавающей запятой = mapfloat((float)pot_filtered, 0.0, 1024.0, REFERENCE_MIN, REFERENCE_MAX);
/*ЧИТАТЬ ДАННЫЕ ДАТЧИКА*/
int Sensor_value = AnalogRead (sensor_pin);
/*УДАЛЕНИЕ ШУМА ДАТЧИКА*/
if(abs(sensor_value-old_sensor_value) > SENSOR_NOISE_LP_THRESHOLD || Sensor_value-last_sensor_value < SENSOR_NOISE_SPIKE_THRESHOLD){ //все в порядке
old_sensor_value = последнее_sensor_value;
последнее_значение_датчика = значение_датчика;
}
else{ //обнаружен всплеск — установить выборку, равную последней
датчик_значение = последнее_значение_сенсора;
}
/*ЛИНЕАРИЗОВАТЬ ВЫХОД ДАТЧИКА В САНТИМЕТРАХ*/
Sensor_value = Макс (1, Sensor_value); //избегаем диви





























