ESP32とMicroPythonのADCでジョイスティックの位置をPCのPyQtGraphに表示する

Share on:

MicroPythonを入れたESP32でAD変換を使ってみるためにジョイスティックの位置を読み取ってみました。シリアル通信でPCに送られてきた文字列をただ表示するだけじゃ面白くないのでPyQtGraphのグラフに表示してみました。

マイコンからの受信データの確認

AD変換した値をシリアル通信で送信するプログラムを作成しました。プログラムはAD変換の設定をした後に値を送り続けるという単純なプログラムです。VS codeのステータスバーのRunをクリックするとデータが送られてきてターミナルに表示されました。このデータを処理してパソコン側でグラフとして表示してみます。

パソコン側でのグラフ表示

以前作成したPyQtGraphを使ったコードを流用して作成しました。受信した値はnumpy配列の最後のインデックスに入れていき、最初のインデックスのデータは削除することで、グラフに軌跡が残るように表示してみました。グラフの描画はPyQtのQTimerで一定間隔で行うようにしています。

1self.plot_data['X'] = np.append( self.plot_data['X'][1:], float(splited[1]) )
2self.plot_data['Y'] = np.append( self.plot_data['Y'][1:], float(splited[3]) )

所感

マイコン側もパソコン側もPythonでコードを書くことができるのは便利ですね。ロボットの制御とかにも使ってみたいと思います。今回作ったプログラムは表示できればよかっただけなので、PC側のソフトでデータの取りこぼしがあるかもしれません。シリアル通信についてはもう少し調べてみたいと思います。

マイコンのコード

 1import time
 2from machine import Pin, ADC
 3
 4# ADC settings
 5adc_x = ADC(Pin(34))
 6adc_y = ADC(Pin(35))
 7adc_x.atten(ADC.ATTN_11DB)
 8adc_y.atten(ADC.ATTN_11DB)
 9
10while True:
11    x = adc_x.read()
12    y = adc_y.read()
13
14    print("x", x, "y", y)
15
16    time.sleep_ms(100)

パソコンのコード

 1# -*- coding: utf-8 -*-
 2import sys
 3from PyQt5 import QtCore, QtGui, QtWidgets
 4from pyqtgraph import PlotWidget
 5import pyqtgraph
 6import numpy as np
 7import serial
 8
 9class MainWindow(QtWidgets.QMainWindow):
10    def __init__(self, parent=None):
11        super(MainWindow, self).__init__(parent)
12
13        self.plot_data = { 'X':np.full(10, 0), 'Y':np.full(10, 0) }
14
15        self.resize(600, 600)
16        self.setStyleSheet("QMainWindow {background: 'white';}")
17        self.serial = serial.Serial('COM3', 115200, timeout=None)
18
19        # leyout
20        self.centralwidget = QtWidgets.QWidget(self)
21        self.setCentralWidget(self.centralwidget)
22        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
23        self.horizontalLayout = QtWidgets.QHBoxLayout()
24        self.horizontalLayout2 = QtWidgets.QHBoxLayout()
25        self.verticalLayout.addLayout(self.horizontalLayout)
26        self.verticalLayout.addLayout(self.horizontalLayout2)
27        
28        # pot widget
29        self.plotwidget = PlotWidget(self)
30        self.plotwidget.setBackground("#FFFFFFFF")
31        plotitem = self.plotwidget.plotItem
32        plotitem.setLabels(bottom='X', left='Y')
33        plotitem.getAxis('bottom').setPen( pyqtgraph.mkPen(color='#000000') )
34        plotitem.getAxis('left').setPen( pyqtgraph.mkPen(color='#000000') )
35        plotitem.setRange(xRange = (0, 4095), yRange = (0, 4095), padding = 0)
36        
37        # leyout
38        self.horizontalLayout.addWidget(self.plotwidget)
39
40        # timer
41        self.timer = QtCore.QTimer()
42        self.timer.timeout.connect(self.update_data)
43        self.timer.start(50)
44
45    def update_data(self):
46        # stop timer
47        self.timer.stop()
48
49        # clear
50        self.plotwidget.clear()
51
52        # get serial
53        line = self.serial.readline()
54        splited = line.split()
55        self.plot_data['X'] = np.append( self.plot_data['X'][1:], float(splited[1]) )
56        self.plot_data['Y'] = np.append( self.plot_data['Y'][1:], float(splited[3]) )
57
58        # set data
59        self.plotwidget.addItem(
60            pyqtgraph.PlotDataItem(
61                x=self.plot_data['X'], y=self.plot_data['Y'], 
62                pen=pyqtgraph.mkPen(color='#000000', width=10), antialias=True
63            )
64        )
65        
66        print(self.plot_data['X'], self.plot_data['Y'])
67
68        # start timer
69        self.timer.start(50)
70
71def main():
72    app = QtWidgets.QApplication(sys.argv)
73    mainwindow = MainWindow(None)
74    mainwindow.show()
75    app.exec()
76
77if __name__ == '__main__':
78    main()

関連記事