Le contenu de cet article est en version bêta et est susceptible de changer. Dans cet article, nous allons effectuer une régression linéaire sur le traçage de lignes en utilisant Version éducative LEGO® MINDSTORMS EV3 (ci-après EV3) et l'environnement Python. Veuillez vous référer à l'article précédent pour la construction de l'environnement.
Apprentissage automatique avec EV3 Partie 1 Construction de l'environnement: ici Apprentissage automatique avec EV3 Partie 2 Régression linéaire: cet article Machine learning avec classification EV3 Partie 3: à venir
PC Windows10 Python 3.7.3 Environnement de développement VisualStudioCode
EV3 ev3dev
La régression linéaire est une méthode d'analyse qui trouve la ligne droite qui correspond le mieux au groupe de données lorsqu'il existe une distribution de données.
Lorsqu'il existe deux types de groupes de données comme indiqué ci-dessous, les résultats peuvent être obtenus en traçant une ligne qui correspond bien aux données et en faisant des prédictions même pour les données que vous ne possédez pas.
Le but principal est d'effectuer une régression linéaire avec EV3, mais il est nécessaire de relier le fonctionnement d'EV3 à l'inférence par régression linéaire. Cette fois, l'objectif est d'effectuer un traçage de ligne avec un fonctionnement régulier tout en effectuant une régression linéaire selon la procédure suivante.
Le modèle EV3 utilisé cette fois sera le modèle suivant. Un capteur de couleur est fixé à l'avant de la carrosserie, permettant le traçage des lignes. Un capteur gyroscopique est fixé à l'arrière de la carrosserie pour acquérir l'angle auquel la carrosserie fait face. La trajectoire de déplacement est dessinée en utilisant la valeur de cet angle.
Le cours elliptique qui se déroule cette fois utilise les cours suivants.
Les bibliothèques à utiliser en plus de ev3dev cette fois sont les suivantes.
Numpy
Numpy est une bibliothèque très populaire pour faire des calculs numériques en Python.
Il devient possible d'effectuer facilement un traitement de calcul de tableau tel que le calcul vectoriel et matriciel.
Cette fois, il est utilisé lors du stockage des données de capteur acquises dans un tableau ou lors de l'exécution d'un calcul.
Procédure d'installation
pip install numpy
matplotlib matplotlib est une bibliothèque souvent utilisée pour dessiner des graphiques en Python. Cette fois, il est utilisé pour tracer l'itinéraire de déplacement en fonction des données du capteur gyroscopique. Ci-dessous la procédure d'installation
pip install matplotlib
Pandas
Pandas est une bibliothèque pour gérer efficacement les données en Python.
Cette fois, il est utilisé pour lire le fichier csv.
Ci-dessous la procédure d'installation
pip install pandas
sciki-learn scikit-learn est une bibliothèque d'apprentissage automatique Python. La classification, la régression, le regroupement, etc. peuvent être mis en œuvre relativement facilement. Ci-dessous la procédure d'installation
pip install scipy
pip install scikit-learn
Cette fois, créez les trois programmes suivants.
data_get_gyro.py
course.py
LinearRegression.py
Puisqu'il existe une limite aux spécifications d'EV3, la configuration est telle que le calcul numérique et le traitement de régression linéaire sont exécutés côté PC et la valeur du résultat du traitement est envoyée à EV3. La relation entre chaque programme est illustrée dans la figure ci-dessous.
Le programme latéral EV3 est un programme qui est réellement exécuté par EV3. Principalement, l'EV3 implémentera le traçage de ligne avec une valeur de virage spécifiée, le transfert d'un capteur gyroscopique à l'aide de la communication par prise et la réception de commentaires à un point de retournement.
Créez le programme secondaire EV3 data_get_gyro.py
dans l'espace de travail sur VSCode ci-dessous. Reportez-vous à Article précédent pour savoir comment créer un espace de travail et transférer le code source vers EV3.
import time
import socket
import sys
from ev3dev2.button import Button
from ev3dev2.motor import LargeMotor, OUTPUT_B, OUTPUT_C
from ev3dev2.sensor import INPUT_2, INPUT_3
from ev3dev2.sensor.lego import GyroSensor, ColorSensor
power range:-1050 -> 1050, turn_ratio range:-100 -> 100
def linetrace_steer(power, turn_ratio):
global data_cycle
if color.reflected_light_intensity > 30:
ev3_motor_steer(power, turn_ratio*-1)
else:
ev3_motor_steer(power, turn_ratio)
time.sleep(0.1)
data_cycle += 1
def ev3_motor_steer(power, turn_ratio):
if turn_ratio < 0:
lm_b.run_forever(speed_sp=power*(1+turn_ratio/50))
lm_c.run_forever(speed_sp=power)
elif turn_ratio > 0:
lm_b.run_forever(speed_sp=power)
lm_c.run_forever(speed_sp=power*(1-turn_ratio/50))
else:
lm_b.run_forever(speed_sp=power)
lm_c.run_forever(speed_sp=power)
def gyro_reset():
time.sleep(1.0)
gyro.mode = 'GYRO-ANG'
gyro.mode = 'GYRO-RATE'
gyro.mode = 'GYRO-ANG'
time.sleep(1.0)
def dataget():
global fb_steer # feedback steering value
global set_steer
_gyro_data = gyro.value() # gyro data
_gyro_data_str = str(_gyro_data)
s.send(_gyro_data_str.encode())
print(_gyro_data_str)
if ROUND_CHECK < _gyro_data:
while not(button.up):
ev3_motor_steer(0, 0)
if fb_steer is None:
fb_steer = s.recv(1024).decode()
fb_steer_float = float(fb_steer)
print(fb_steer_float)
set_steer = set_steer - fb_steer_float
if button.backspace:
s.close
print('End program')
sys.exit()
print('set_steer = ' + str(set_steer))
# gyro reset
gyro_reset()
fb_steer = None
sensors&motors definition
button = Button()
color = ColorSensor(INPUT_3)
gyro = GyroSensor(INPUT_2)
lm_b = LargeMotor(OUTPUT_B)
lm_c = LargeMotor(OUTPUT_C)
gyro initialize
gyro_reset()
variable initialize
data_cycle = 1 # counter
fb_steer = None # Feedback turn
ROUND_CHECK = 355 # confirm one round
motor initialize
lm_b.reset()
lm_c.reset()
set_power = 200
set_steer = 70
get gyrodate and into array
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(('169.254.207.161', 50010)) # your PC's Bluetooth IP & PORT
while not(button.backspace):
linetrace_steer(set_power, set_steer)
if data_cycle % 4 == 0: # gyro_get_frequency
dataget()
lm_b.stop(stop_action='brake')
lm_c.stop(stop_action='brake')
print('End program')
sys.exit()
s.connect (('169.254.207.161', 50010))
décrit dans la seconde moitié sera réécrit plus tard en fonction de l'environnement.Dans le programme de données de parcours de comparaison, des données similaires à la trajectoire d'origine sont générées pour comparaison avec l'ellipse de la trajectoire dessinée par la trace de ligne.
Ce programme n'est pas exécuté directement, mais est créé pour être importé dans LinearRegression.py, qui sera créé ultérieurement.
Créez un dossier appelé programme
sur le bureau de votre PC, créez course.py
en tant que document texte et décrivez le contenu suivant.
import numpy as np
import matplotlib.pyplot as plt
def original_course(element_cnt, plot_interval):
_element_cnt_f = element_cnt % 10 # element count fraction
_element_cnt_unf = (element_cnt - _element_cnt_f)
_element_cnt_s = _element_cnt_unf / 10 # element count one course section
plot_interval = plot_interval + (_element_cnt_f*(plot_interval/_element_cnt_unf))
_xcount = 1
_ycount = 1
_rcount = 1
global P
P = np.zeros(0)
global Q
Q = np.zeros(0)
# 1
while not _xcount > _element_cnt_s:
_x1 = plot_interval * -1*_xcount
_y1 = 0
P = np.append(P, _x1)
Q = np.append(Q, _y1)
_xcount += 1
# 2
while not _xcount > _element_cnt_s * 2:
_x2 = plot_interval * -1*_xcount
_y2 = 0
P = np.append(P, _x2)
Q = np.append(Q, _y2)
_xcount += 1
# 3 cercle
_rcount = 0
while not _rcount > _element_cnt_s:
_a1 = plot_interval*(_element_cnt_s*2) * -1 # cercle centerX
_b1 = plot_interval*_element_cnt_s - plot_interval # cercle centerY & radius
_x3 = _a1 + _b1*np.cos(np.radians(270-(90 / _element_cnt_s*_rcount)))
_y3 = _b1 + _b1*np.sin(np.radians(270-(90 / _element_cnt_s*_rcount)))
P = np.append(P, _x3)
Q = np.append(Q, _y3)
_rcount += 1
# 4
while not _ycount > _element_cnt_s:
_x4 = _x3
_y4 = plot_interval*_ycount + _y3
P = np.append(P, _x4)
Q = np.append(Q, _y4)
_ycount += 1
# 5 cercle
_rcount = 0
while not _rcount > _element_cnt_s:
_a2 = _a1 # cercle centerX
_b2 = _y4 # cercle centerY
_x5 = _a2 + _b1*np.cos(np.radians(180-(90 / _element_cnt_s*_rcount)))
_y5 = _b2 + _b1*np.sin(np.radians(180-(90 / _element_cnt_s*_rcount)))
P = np.append(P, _x5)
Q = np.append(Q, _y5)
_rcount += 1
# 6
_xcount = 1
while not _xcount > _element_cnt_s:
_x6 = _x5 + plot_interval*_xcount
_y6 = _y5
P = np.append(P, _x6)
Q = np.append(Q, _y6)
_xcount += 1
# 7
_xcount = 1
while not _xcount > _element_cnt_s:
_x7 = _x6 + plot_interval*_xcount
_y7 = _y6
P = np.append(P, _x7)
Q = np.append(Q, _y7)
_xcount += 1
# 8 cercle
_rcount = 0
while not _rcount > _element_cnt_s:
_a3 = 0 # cercle centerX
_b3 = _y4 # cercle centerY
_x8 = _a3 + _b1*np.cos(np.radians(90-(90 / _element_cnt_s*_rcount)))
_y8 = _b3 + _b1*np.sin(np.radians(90-(90 / _element_cnt_s*_rcount)))
P = np.append(P, _x8)
Q = np.append(Q, _y8)
_rcount += 1
# 9
_ycount = 1
while not _ycount > _element_cnt_s:
_x9 = _x8
_y9 = plot_interval*_ycount*-1 + _y8
P = np.append(P, _x9)
Q = np.append(Q, _y9)
_ycount += 1
# 10 cercle
_rcount = 0
while not _rcount > _element_cnt_s:
_a4 = 0 # cercle centerX
_b4 = _b1 # cercle centerY
_x10 = _a4 + _b1*np.cos(np.radians(0-(90 / _element_cnt_s*_rcount)))
_y10 = _b4 + _b1*np.sin(np.radians(0-(90 / _element_cnt_s*_rcount)))
P = np.append(P, _x10)
Q = np.append(Q, _y10)
_rcount += 1
if __name__ == '__main__':
original_course(100, 30)
plt.figure()
plt.plot(P, Q, '-', color='blue')
plt.show()
Le programme côté PC trace l'itinéraire de déplacement à partir des données du capteur gyroscopique envoyées par EV3 et le compare avec les données de parcours d'origine pour calculer l'erreur. De plus, l'erreur calculée et la valeur de rotation sont enregistrées dans un fichier CSV, et la valeur de rotation appropriée est renvoyée à EV3 suite à l'inférence par régression linéaire.
Créez LinearRegression.py
comme document texte dans le dossier programme
de la même manière que course.py et décrivez le contenu suivant.
import socket
import course # course.py
import sys
import csv
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import os.path
from sklearn import linear_model
clf = linear_model.LinearRegression()
Feedback phase function
def feedback(element_cnt,
plot_interval,
min_steer,
X,
cur_steer,
steers,
errors):
cnt = 1
limit = 100
# from course.py course coordinate point
if not element_cnt == 1:
course.original_course(element_cnt, plot_interval)
_X_abs = np.abs(X) # run coordinate point 'x'
_P_abs = np.abs(course.P) # from course.py course coordinate point 'x'
_X_ave = _X_abs.mean() # average
_P_ave = _P_abs.mean() # average
_point_error = np.abs(_X_ave - _P_ave) # point_average_error
# add feedback_data to csv
writedata = [cur_steer, _point_error]
with open('datafile.csv', 'a', newline='') as f:
writer = csv.writer(f)
writer.writerow (writedata) # Ecrire des données
steers = np.append(steers, cur_steer) # append steer data
errors = np.append(errors, _point_error) # append error data
print('steers = {}'.format(steers))
print('errors = {}'.format(errors))
print('len(errors) = {}'.format(len(errors)))
if len(errors) > 1:
if errors[-1] > errors[-2] and steers[-1] > min_steer:
min_steer = steers[-1]
errors = errors.reshape(-1, 1)
clf.fit(errors, steers) # linear regression
while cnt < limit:
ave_error = np.average(errors)
input_error = cnt/(cnt+1) * ave_error
input_error = input_error.reshape(-1, 1)
predict_steer = clf.predict(input_error)
if predict_steer > min_steer:
break
cnt += 1
str_prd_steer = str(predict_steer[0])
print('predict_steer = {}'.format(str_prd_steer))
conn.send(str_prd_steer.encode())
return predict_steer[0], min_steer, steers, errors
else:
cur_steer = cur_steer*2/3
print('next_steer = {}'.format(cur_steer))
conn.send(str(cur_steer).encode())
return cur_steer, min_steer, steers, errors
variable initialize
gyro = np.zeros(0)
element_cnt = 1 # element count
plot_interval = 30 # plot point interval
X = np.zeros(0)
Y = np.zeros(0)
steers = np.zeros(0)
errors = np.zeros(0)
Lap = 0
ROUND_CHECK = 355 # confirm one round
ini_steer = 70
cur_steer = ini_steer
generate
if os.path.exists('datafile.csv') == False:
writedata = ['steer', 'error']
f = open ('datafile.csv', 'w', newline = '') # fichier ouvert
writer = csv.writer(f)
writer.writerow (writedata) # Ecrire des données
f.close()
data = pd.read_csv ("datafile.csv", sep = ",") # lire le fichier csv
steer_data = data.loc [:, 'steer']. values # Définit la valeur de pivot dans la variable objectif (remplacez les données dans la colonne de direction)
error_data = data ['error'] .values # Définit une erreur dans la variable explicative (remplacez les données dans la colonne d'erreur)
min_steer = 0 # valeur minimale
for cnt, data in np.ndenumerate(steer_data):
if error_data[cnt] < 900:
steers = np.append (steers, data) # Substituer des valeurs autres que bien sûr
elif data > min_steer:
min_steer = data # mise à jour minimum
for data in error_data:
if data < 900:
errors = np.append (errors, data) # Remplacez une valeur autre que course out
Main program
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('169.254.207.161', 50010)) # your PC's Bluetooth IP & PORT
s.listen(1)
print('Start program...')
while True:
conn, addr = s.accept()
with conn:
if len(errors) > 1:
values = feedback(element_cnt,
plot_interval,
min_steer,
X,
cur_steer,
steers,
errors)
cur_steer = values[0]
min_steer = values[1]
steers = values[2]
errors = values[3]
else:
conn.send(str(cur_steer).encode())
while True:
gyro_data = conn.recv(1024).decode()
if not gyro_data:
break
gyro_data_float = float(gyro_data) # change type
gyro = np.append(gyro, gyro_data_float) # gyro angle
np.set_printoptions(suppress=True)
cosgy = plot_interval * np.cos(np.radians(gyro)) * -1
singy = plot_interval * np.sin(np.radians(gyro))
X = np.append(X, np.sum(cosgy[0:element_cnt]))
Y = np.append(Y, np.sum(singy[0:element_cnt]))
if ROUND_CHECK < gyro_data_float:
plt.figure()
plt.plot(X, Y, '-', color='blue')
print('Plot file output')
print(str(Lap) + '-plot.png')
plt.savefig(str(Lap) + '-plot.png')
values = feedback(element_cnt,
plot_interval,
min_steer,
X,
cur_steer,
steers,
errors)
cur_steer = values[0]
min_steer = values[1]
steers = values[2]
errors = values[3]
# reset phase
element_cnt = 0
X = np.zeros(0)
Y = np.zeros(0)
gyro = []
plt.clf() # figure clear
plot_interval = 30
Lap += 1
element_cnt = element_cnt + 1 # Element count
# Ecrire en csv avec une erreur de 1000 après avoir déraillé
if element_cnt > 1:
writedata = [cur_steer, 1000]
f = open('datafile.csv', 'a', newline='')
writer = csv.writer(f)
writer.writerow(writedata)
f.close()
print('End program')
sys.exit()
Le s.bind (('169.254.207.161', 50010))
décrit dans la seconde moitié est modifié par la procédure suivante en fonction de l'environnement comme le programme annexe EV3.
Les données sont échangées entre le programme côté EV3 et le programme côté PC via une communication socket afin de donner un retour sur la valeur du capteur gyroscopique et le point de retournement, mais l'adresse IP décrite dans le programme est modifiée en fonction de l'environnement. Il y a un besoin de.
Lorsque le PC et l'EV3 sont connectés via Bluetooth, l'adresse locale du lien «169.254.XXX.YYY» est attribuée. Suivez les étapes ci-dessous pour connaître l'adresse IP.
Il est nécessaire de changer la description suivante dans la seconde moitié de data_get_gyro.py
.
s.connect(('169.254.207.161', 50010)) # your PC's Bluetooth IP & PORT
L'édition réelle du programme est la suivante.
Après avoir modifié la description, transférez l'espace de travail vers EV3 sur VS Code.
Il est nécessaire de changer la description suivante dans la dernière moitié de "LinearRegression.py".
s.bind(('169.254.207.161', 50010)) # your PC's Bluetooth IP & PORT
L'édition proprement dite du programme est la suivante.
Après avoir créé trois programmes et modifié la description des deux adresses IP, exécutez le programme. Voici la procédure d'exécution.
cd Desktop \ program
à partir de l'invite de commande (\ est synonyme de \ mark)
python LinearRegression.py
à l'invite de commandeInstallez EV3 au début du cours
Ouvrez le terminal SSH de l'EV3 connecté sur VS Code et exécutez cd ev3 workspace /
Exécutez python3 data_get_gyro.py
dans le terminal SSH
À chaque tour, EV3 s'arrête près du point de départ, alors appuyez sur le bouton supérieur du bloc intelligent pour démarrer le tour suivant.
Après 6 tours, le résultat est le suivant. L'invite de commande affiche la valeur de virage et l'erreur, le nombre de données (nombre de tours) et la valeur de virage suivante pour chaque tour. La valeur du capteur gyroscopique qui est envoyée au programme côté PC est affichée sur le terminal SSH sur VSCode.
En ce qui concerne l'opération, comme le montre la vidéo suivante, vous pouvez voir que le tracé de la ligne devient plus fluide et que la vitesse du tour devient plus rapide à chaque tour.
Lorsque vous ouvrez le fichier CSV qui stocke les données dans Excel, les données sont résumées comme suit.
Il est possible de le représenter graphiquement dans le programme, mais cette fois j'ai créé un graphique de régression linéaire dans Excel. On peut voir que l'erreur à une certaine valeur de rotation peut être prédite dans une certaine mesure.
Cette fois, nous avons effectué un tracé de ligne et une régression linéaire pour trouver la valeur de virage à partir de la trajectoire de déplacement. Si vous pouvez obtenir deux données liées, vous pouvez effectuer une prédiction de cette manière. C'est une méthode qui peut être appliquée, bien qu'il soit nécessaire de considérer le type de données à utiliser pour évaluer le problème à améliorer et le personnaliser.
La prochaine fois, nous classerons à partir des données numériques RVB acquises par le capteur de couleur et jugerons plusieurs types de couleurs.
Recommended Posts