ディスプレイの数が増えてくると(液タブとかも)マウス・ポインタの迷子が多発します.
そんなときに便利なのが,ご存じxeyesです.
でも,画面の一部を占有されるのはうれしくないし,ディスプレイ自体が複数あるので,どこに置くのがよいか決めるのも難しい...
と,いうわけでM5Stackを使って幸せになってみます.
全体構成
PC側のプログラム
Windows上でマウスの現在座標値を受け取って,UDPソケットで通信します.
Pythonで実装しました.
送るデータは(X座標値,Y座標値)
のみです.
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フレームワークを使っています.
#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);
}