====== 10. Strojové učení ======
===== Cíle cvičení =====
* Seznámení výstupem z 9DOF IMU MPU9250
* Rozpoznání náklonu akcelerometru
* Interpretace IMU dat
===== Další zdroje =====
* https://github.com/tuupola/micropython-mpu9250
* https://randomnerdtutorials.com/raspberry-pi-pico-i2c-scanner-micropython/
* [[https://pythonnumericalmethods.berkeley.edu/notebooks/chapter16.00-Least-Squares-Regression.html|Least Squares Regression]]
* http://www.bzarg.com/p/how-a-kalman-filter-works-in-pictures/
* {{ :courses:b0b37nsi:tutorials:1704.06053.pdf |Using Inertial Sensors for Position and Orientation Estimation}}
===== Rozpoznání náklonu z akcelerometru =====
Cílem této úlohy je natrénovat SVM klasifikátor tak, aby rozpoznal přibližné naklonění akcelerometru. Abychom toho mohli dosáhnout, je třeba projít těmito kroky:
- Získání trénovacích dat
- Označení trénovacích dat (štítky)
- Natrénování modelu
- Predikce v reálném čase
==== Získání trénovacích dat ====
Modul 10 DOF IMU je připojen k RPi pomocí sběrnice I2C. Vyberte vhodné piny (např. ''SDA'' na pin ''0'' a ''SCL'' na pin ''1'') a modul připojte, pro napájení zvolte pin ''VSYS''. Z [[https://github.com/tuupola/micropython-mpu9250|githubu]] stáhněte moduly [[https://github.com/tuupola/micropython-mpu9250/blob/master/mpu9250.py|mpu9250.py]], [[https://github.com/tuupola/micropython-mpu9250/blob/master/mpu6500.py|mpu6500.py]] a [[https://github.com/tuupola/micropython-mpu9250/blob/master/ak8963.py|ak8963.py]]. Stažené moduly uložte do paměti RPi. Nádledující kód přečte data ze všech dostupných senzorů.
import utime
from machine import I2C, Pin
from mpu9250 import MPU9250
i2c = I2C(0, scl=Pin(1), sda=Pin(0))
sensor = MPU9250(i2c)
print("MPU9250 id: " + hex(sensor.whoami))
while True:
print(sensor.acceleration)
print(sensor.gyro)
print(sensor.magnetic)
print(sensor.temperature)
utime.sleep_ms(1000)
Jedná se o data typu float, takže je nutné promyslet, jak data efektivně přenést a případně uložit. S ohledem na rychlost přenosu a potřebnou přesnost může být výhodné přenášet data binárně.
V Pythonu pak lze pro přenost a dekódování dat ve strukturách podobným jako v C využít knihovny [[https://docs.python.org/3/library/ctypes.html|ctypes]] nebo [[https://docs.python.org/3/library/struct.html|struct]].
=== PC - příjem a uložení ===
Pro offline analýzu uložte data do souboru ve formátu CSV. To lze udělat např. pomocí modulu [[https://docs.python.org/3/library/csv.html|csv]]. Následující kód předpokládá, že jsou data získána (ze sériového portu, z databáze, z API rozhraní služby) ve formě seznamu.
import csv
header = ['acc_x', 'acc_y', 'acc_z', 'gyr_x', 'gyr_y', 'gyr_z']
data = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
with open('data.csv', 'w', encoding='UTF8', newline='') as f:
writer = csv.writer(f)
# write the header
writer.writerow(header)
# write the data
writer.writerow(data)
==== Přiřazení štíků ====
Rozpoznání náklonu akcelerometru je velmi jednoduchá klasifikační úloha. Hledané třídě (náklonu) odpovídá kombinace diskrétní hodnot, získaných z IMU. Nasbíraná data rozdělíme do tříd tak, že do jednotlivých řádků doplníme jednoznačný štítek, např. takto
* 0 - vodorovně
* 1 - náklon dopředu
* 2 - náklon dozadu
Štítky nemusí být číselné, může to být i textový řetězec. Příklad výsledného souboru:
acc_x,acc_y,acc_z,gyr_x,gyr_y,gyr_z,class
0.076416015625,-0.04150390625,1.00341796875,0.030517578125,6.591796875,0.9307861328125,0
0.1044921875,-0.04052734375,0.851318359375,-2.95257568359375,9.6435546875,-0.38909912109375,0
...
0.173583984375,0.426513671875,0.89892578125,2.99072265625,10.36834716796875,1.8768310546875,1
0.146728515625,0.327392578125,0.689697265625,3.692626953125,4.31060791015625,4.6844482421875,1
...
-0.076904296875,-0.660888671875,0.782958984375,5.767822265625,2.02178955078125,2.4566650390625,2
-0.1162109375,-0.67138671875,0.619384765625,6.44683837890625,-15.106201171875,-0.61798095703125,2
==== Trénování klasifikátoru ====
Uložená data použijeme jako trénovací (70% dat) a testovací (30% dat) množinu pro získání klasifikátoru.
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn import svm
import pickle
dataset = pd.read_csv('data.csv')
X = dataset.iloc[:, [0, 1, 2, 3, 4, 5]].values
y = dataset.iloc[:, [6]].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.30, random_state = 0)
clf = svm.SVC(kernel='linear')
clf.fit(X_train, np.ravel(y_train))
Klasifikátor je možné uložit pro pozdější použití např. pomocí modulu [[https://docs.python.org/3/library/pickle.html|pickle]].
filename = 'model.sav'
pickle.dump(clf, open(filename, 'wb'))
==== Predikce ====
Pokud máme k dispozici model, je možné použít předikci z dat, které v reálném čase získáváme z IMU:
clf = pickle.load(open('model.sav', 'rb'))
# ziskani dat
D = [[data.acc_x, data.acc_y, data.acc_z, data.gyr_x, data.gyr_y, data.gyr_z]]
# predikce
print(clf.predict(D))
===== IMU interpretace =====
{{:courses:b0b37nsi:tutorials:7e35672ed3e05191cb6aea0d69cf6ebb98bcb88a.png?400|}}
pitch = 180 * atan2(acc_x, sqrt(acc_y*acc_y + acc_z*acc_z))/PI;
roll = 180 * atan2(acc_y, sqrt(acc_x*acc_x + acc_z*acc_z))/PI;
Vyzkoušejte vypočítat hodnoty a zamyslet se nad tím, jaké výsledky získáváte.
Další linky:
https://silo.tips/download/application-note-imu-visualization-software
https://github.com/jarzebski/Arduino-ADXL345
http://davidegironi.blogspot.com/2013/02/avr-atmega-mpu6050-gyroscope-and.html#.YnpJnZYzXrc
https://www.instructables.com/Arduino-MPU6050-GY521-6-Axis-Accelerometer-Gyro-3D/
https://www.slideshare.net/dibaowang/imu-general-introduction
===== Kód pro vizualizaci dat z gyroskopu =====
Předpokládejme, že ve třech prvních sloupcích CSV souboru jsou data přečtená z gyroskopu. Jejich vizualizaci můžeme provést např. takto:
from mpl_toolkits import mplot3d
import pandas as pd
import matplotlib.pyplot as plt
data = pd.read_csv('data1.csv')
ax = plt.axes(projection='3d')
x = data.iloc[:,0]
y = data.iloc[:,1]
z = data.iloc[:,2]
ax.scatter3D(x, y, z, color='green')
plt.show()