M5Stackでxeyesしてみたら意外に便利


![1639046047865.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369631/9c47cdc8-197b-b396-55c3-1acdda9427ac.jpeg)

　ディスプレイの数が増えてくると（液タブとかも）マウス・ポインタの迷子が多発します．
そんなときに便利なのが，ご存じxeyesです．
　でも，画面の一部を占有されるのはうれしくないし，ディスプレイ自体が複数あるので，どこに置くのがよいか決めるのも難しい...
　と，いうわけでM5Stackを使って幸せになってみます．

## 全体構成
![m5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369631/5366481a-2f6e-4ff8-59ef-825de642f614.png)


## PC側のプログラム
　Windows上でマウスの現在座標値を受け取って，UDPソケットで通信します．
Pythonで実装しました．
　送るデータは`(X座標値,Y座標値)`のみです．


```python:xpyes.py
import socket
import time
import pyautogui


host = '192.168.0.6'
port = 8080
m5stack = (host, port)

sock = socket.socket(socket.AF_INET, type=socket.SOCK_DGRAM)
sock.connect(m5stack)


while True:
    x, y = pyautogui.position()
#    x = (int)((x / 1980) * 240)
#    y = (int)((y / 1200) * 200)
    pos = "(" + str(x) + "," + str(y) + ")"
    try :
#        print(pos)

        time.sleep(0.1)
        sock.sendto(pos.encode(encoding='utf-8'), m5stack)

    except KeyboardInterrupt:
        sock.close()
        break
```


## マイコン（M5Stack）側のプログラム
UDPソケットでX・Y座標値を受け取って目玉を描くだけです．
Arduinoフレームワークを使っています．

```c++
#include <WiFi.h>
#include <WiFiUDP.h>
#include <M5Stack.h>

void drawEyes();

const char ssid[] = "pi"; //WifiのSSID
const char pass[] = "raspberry"; //Wifiの password

WiFiUDP wifiUdp; 
const int my_port = 8080;  //自身のポート

int16_t drawLeftEyeX=100;
int16_t drawLeftEyeY=120;
int16_t drawRightEyeX=210;
int16_t drawRightEyeY=120;

void setup() {
  M5.begin();
//  M5.Power.begin();
//  M5.Lcd.setTextSize(2);

  WiFi.begin(ssid, pass);
  while( WiFi.status() != WL_CONNECTED) {
    delay(500); 
    M5.Lcd.print("."); 
  }  
  M5.Lcd.println("WiFi connected");
  M5.Lcd.print("IP address = ");
  M5.Lcd.println(WiFi.localIP());
  Serial.println(WiFi.localIP());
  
  wifiUdp.begin(my_port);
  M5.Lcd.fillScreen(TFT_WHITE);
  drawEyes();
  M5.Lcd.fillEllipse(drawLeftEyeX, drawLeftEyeY, 14,18,TFT_BLACK);
  M5.Lcd.fillEllipse(drawRightEyeX, drawRightEyeY, 14,18,TFT_BLACK);
}


void loop(){
  String message;
  
  int16_t pointX=0;
  int16_t pointY=0;

  int num_packet = wifiUdp.parsePacket();
  char packetBuffer[100];
  if (num_packet){
    int len = wifiUdp.read(packetBuffer, num_packet);
    if (len > 0){ packetBuffer[len] = '\0'; }
    //M5.Lcd.println(packetBuffer);
    message = (String)((char*)packetBuffer);
    uint8_t firstSep = message.indexOf(',');
    uint8_t secondSep = message.indexOf(')');
    String a = message.substring(1,firstSep);
    String b = message.substring(firstSep+2, secondSep);
    M5.Lcd.fillEllipse(drawLeftEyeX, drawLeftEyeY, 14,18,TFT_WHITE);
    M5.Lcd.fillEllipse(drawRightEyeX, drawRightEyeY, 14,18,TFT_WHITE);
    pointX = a.toInt();
    pointY = b.toInt();
//    pointX = message.substring(1,firstSep).toInt();
//    pointY = message.substring(firstSep+1, secondSep).toInt();
    drawLeftEyeX = (int16_t)(pointX/12-pointY/50+25);  //1920/(320/2) = 6
    drawLeftEyeY = (int16_t)(pointY/10+120);  //1200/240 = 5
    if(drawLeftEyeX < 40) drawLeftEyeX = 40;
    if(drawLeftEyeX > 120) drawLeftEyeX = 120;
    if(drawLeftEyeY < 40) drawLeftEyeY = 40;
    if(drawLeftEyeY > 175) drawLeftEyeY = 175;

    drawRightEyeX = (int16_t)(pointX/12+pointY/50+160-25);  //1920/(320/2) = 6
    drawRightEyeY = (int16_t)(pointY/10+120);  //1200/240 = 5
    if(drawRightEyeX < 200) drawRightEyeX = 200;
    if(drawRightEyeX > 280) drawRightEyeX = 280;
    if(drawRightEyeY < 40) drawRightEyeY = 40;
    if(drawRightEyeY > 175) drawRightEyeY = 175;

    M5.Lcd.fillEllipse(drawLeftEyeX, drawLeftEyeY, 14,18,TFT_BLACK);
    M5.Lcd.fillEllipse(drawRightEyeX, drawRightEyeY, 14,18,TFT_BLACK);
    Serial.println("message: " + message);
    
    Serial.println("pointX: " + String(pointX));
    Serial.println("pointY: " + String(pointY));
    //M5.Lcd.drawString("pointX: " + String(pointX), 100, 60);
    //M5.Lcd.drawString("pointY: " + String(pointY), 100, 80);
    
  }
  M5.update();
  delay(20);
}

void drawEyes(){
  M5.Lcd.fillEllipse(75,115,75,110, TFT_BLACK);
  M5.Lcd.fillEllipse(75,115,63,94, TFT_WHITE);
  M5.Lcd.fillEllipse(245,115,75,110, TFT_BLACK);
  M5.Lcd.fillEllipse(245,115,63,94, TFT_WHITE);
}
```

## 完成
[![IMAGE ALT TEXT HERE](youtube)](https://www.youtube.com/watch?v=L8rjCVfpZGw)