適当のごった煮

Pythonと境界標とQGISを中心にいろいろと

Arduino Nano(Uno)でジョイスティックマウスを作る

スポンサードリンク

Arduino Nanoを使ったジョイスティックマウスを作りました。Arduino Unoでも動作しました。

youtu.be

実体部分は写真のような感じです。

f:id:tekito-gottani:20181108135131j:plain

Arduinoには、MouseやKeyboardというライブラリがあって、Arduino Leonardoなど、ATMEGA32U4というチップを使っていれば、Arduino自身がマウスやキーボードとしてコンピュータに認識されるHIDデバイスになることができます。

しかし、その機能を使ってスケッチを書き込むと、すぐにマウスやキーボードとして機能してしまい、スケッチを調整するときに結構手間がかかるようです。

自分が持っているUnoやNanoでなんとかジョイスティックマウスを作れないかネットを調べていると、英語ですがPC MOUSE MADE WITH ARDUINO UNO AND JOYSTICKというサイトが見つかりました。

概要としては、ジョイスティックの数値をArduinoからシリアルでコンピュータに送り、Javaの機能を使ってシリアルデータの受信とマウス動作をしているようです。

このJavaの部分をPythonに置き換えれば同じことができると考え、さっそくpySerialPyAutoGUIをインストールして実験に取り掛かりました。

実験といっても、アナログジョイスティックDIP化キット、Arduino、pySerial、PyAutoGUIのすべてが事前の想定やドキュメントに記載されている通りに動作したためジョイスティックを使ったマウス動作はすぐに完成しました。

しかし、マウス移動量の調整が難しく、ほんの少し動かしたつもりでも大きく動いてしまうことが多く、配列を使ってそこそこ思うように動かせるところまで行きましたが、細かな移動に関してはまだまだ改善の余地がありそうです。

動作を終了させるときは、PyAutoGUIのフェイルセーフ機能を使って画面左上にカーソルを持っていって例外を出して終わらせます(上記動画でもそのように終わらせています)。

Arduinoは単純にジョイスティックの入力を移動量にmapしてシリアル出力しているだけです。ただし、ジョイスティックの中心に幅があるので、その周辺範囲では動かないようにしています。

int PinX = 1;
int PinY = 2;

// マウス移動量配列
int idou[] = {0, -200, -50, -50, -25, -25, 25, 25, 50, 50, 200};

int valmap(int val){
  if (val > 450 and val < 565){ // ジョイスティック中心範囲
    return(0);
  } else{
    return(map(val, 0, 1023, 1, sizeof(idou)/sizeof(int)-1));
  }
}

void setup() {
  Serial.begin(9600);
}

void loop() {
  int valx, valy, x, y;
  
  while (true){
    delay(200);
    valx = analogRead(PinX);
    valy = analogRead(PinY);

    x = valmap(valx);
    y = valmap(valy);
    
    Serial.print(idou[x]);
    Serial.print(" ");
    Serial.println(idou[y]);
  }
}

PythonもpySerialとPyAutoGUIがとてもよくできているので、それらの機能を単純に使うだけという感じです。特にpySerialがシリアル接続を検出するツールを持っているので大変便利です。

# -*- coding: utf-8 -*-

import serial
import serial.tools.list_ports
import pyautogui

nano = False
info_list = serial.tools.list_ports.comports()
for info in info_list:
    if 'CH340' in info.description: # Unoの場合は「Arduino」で検索
        nano = True
        dev = info.device
        
if nano:
    ser = serial.Serial(dev)
    while True:
        line = ser.readline()
        x, y = line.decode('shift-jis').split()
        pyautogui.moveRel(int(x), int(y))
        print(x, y)
    ser.close()

USBにArduino Nanoを挿したときのデバイスマネージャー上での表示
f:id:tekito-gottani:20181108141147j:plain